What does [[ $something = {{* ]] do in bash? - bash

Found this expression in some shell scripts. What does the double-curly brace star "{{*" mean?
if [[ "$_DIR" = {{* ]]
I've looked through http://www.gnu.org/software/bash/manual/bash.html and tried searching for it, but can't find an explanation.

This means: "if $_DIR" expands to a string starting with "{{"...
Thus, {{* doesn't actually mean anything to bash at all, more than if you wrote
for file in {{*; do printf '%s\n' "$file"; done
...would mean that {{* had any more meaning to bash than "all files whose names start with two curly braces".
Search for "pattern matching" in BashFAQ #31 for more on [[ and how it's extended to offer functionality not present in test, including both glob-style pattern matching and native regular expression support.
Alternately, look for [[…]] in the Conditional Constructs section of the bash manual.
Incidentally, the POSIX sh equivalent to this would be:
case $_DIR in
{{*) echo "put the true branch here" ;;
*) echo "put the false branch here" ;;
esac

Related

bash why no match with number on regexp

I'm curious why this code does not match -- take the "then" branch. It echos "no match" Can you please advise?
#!/bin/bash
suffix="2"
if [[ $suffix =~ "^[0-9]+$" ]]
then
echo "match"
else
echo "no match"
fi
Quoting the right-hand side of an = or =~ operation within [[ ]] in modern (3.2+) releases of bash makes the string literal -- ie. no longer a regex or pattern.
From the manual:
Any part of the pattern may be quoted to force the quoted portion to be matched as a string.
For consistent behavior across releases supporting =~ (if one needs to support versions prior to 3.2), accepted best practice is to put your regex in a variable, and use that variable unquoted on the right-hand side of =~:
re='^[0-9]+$'
[[ $suffix =~ $re ]]

How to use [[ == ]] properly to match a glob?

Bash's manpage teaches that [[ == ]] matches patterns. In Bash therefore, why does the following not print matched?
Z=abc; [[ "$Z" == 'a*' ]] && echo 'matched'
The following however does indeed print matched:
Z=abc; [[ "$Z" == a* ]] && echo 'matched'
Isn't this exactly backward? Why does the a*, without the quotes, not immediately expand to list whatever filenames happen to begin with the letter a in the current directory? And besides, why doesn't the quoted 'a*' work in any case?
Glob pattern must not be quoted to make it work.
This should also work with just glob pattern out of quote whereas static text is still qupted:
[[ "$Z" == "a"* ]] && echo 'matched'
matched
[[ "$Z" == "ab"* ]] && echo 'matched'
matched
Explanation snippet from man page:
When the == and != operators are used, the string to the right of
the operator is considered a pattern and matched according to the
rules described below under Pattern Matching. If the shell option
nocasematch is enabled, the match is performed without regard to
the case of alphabetic characters. The return value is 0 if the
string matches (==) or does not match (!=) the pattern, and 1
otherwise. Any part of the pattern may be quoted to force it to be
matched as a string.
Additionally, one of the reasons to use [[ over [ is that [[ is a shell built-in and thus can have its own syntax and doesn't need to follow the normal expansion rules (which is why the arguments to [[ aren't subject to word-splitting for example).
While the existing answer is correct, I don't believe that it tells the full story.
Globs have two uses. There is a difference in behaviour between globs inside a [[ ]] construct which test the contents of a variable against a pattern and other globs, which expand to list a range of files. In either case, if you put quotes around character, it will be interpreted literally and not expanded.
It is also worth mentioning that the variable on the left hand side doesn't need to be quoted after the [[, so you could write your code like this:
Z=abc; [[ $Z == a* ]] && echo 'matched'
It is also possible to use a single = but the == looks more familiar to those coming from other coding backgrounds, so personally I prefer to use it in bash as well. As mentioned in the comments, the single = is the more widely compatible, as it is used to test string equality in all of POSIX-compliant shells, e.g. [ "$a" = "abc" ]. For this reason you may prefer to use it in bash as well.
As always, Greg's wiki contains some good information on the subject of pattern matching in bash.

Why can you use -eq in Bash conditionals without adding a '$' before a variable name?

I was running some Bash conditional scripts and discovered if I run this:
#!/bin/bash
read foo
if [[ foo -eq 1 ]]; then
echo "A"
fi
if [[ foo -eq 2 ]]; then
echo "B"
fi
The conditionals work fine under Bash 4.2.25 without the use of $foo. Why does this work without referencing the variable with a $?
From the description of bash Conditional Constructs, it says that [[ expression ]] performs arithmetic expansion of the expression. If you then find the section on Shell Arithmetic it says:
Within an expression, shell variables may also be referenced by name without using the parameter expansion syntax.
"parameter expansion syntax" refers to putting a $ before the name.

Bash glob in string comparison

The other day I was struggling with an if statement. Turns our my variable had a white space at the beginning. So I tried to conquer this with the following code but I am having no luck.
if [ "$COMMAND_WAIT" == "*REBOOT" ]; then
sudo /etc/kca/scripts/reboot.sh
echo "REBOOTING"
fi
Should I be able to wildcard this statement or is there another way around this?
The following should work. It uses [[ instead of [, and no quotes around the pattern.
if [[ "$COMMAND_WAIT" == *REBOOT ]]; then
sudo /etc/kca/scripts/reboot.sh
echo "REBOOTING"
fi
[[ expression ]] is a compound expression, with special rules regarding expansions and quoting. In contrast, [ is a builtin command, i.e. *REBOOT will be expanded as a pathname. In most cases, it's easier to use [[ instead of [.

What's the different between "[]" and "[[]]" [duplicate]

This question already has answers here:
Are double square brackets [[ ]] preferable over single square brackets [ ] in Bash?
(10 answers)
Closed 4 years ago.
I looked at bash man page and the [[ says it uses Conditional Expressions. Then I looked at Conditional Expressions section and it lists the same operators as test (and [).
So I wonder, what is the difference between [ and [[ in Bash?
[[ is bash's improvement to the [ command. It has several enhancements that make it a better choice if you write scripts that target bash. My favorites are:
It is a syntactical feature of the shell, so it has some special behavior that [ doesn't have. You no longer have to quote variables like mad because [[ handles empty strings and strings with whitespace more intuitively. For example, with [ you have to write
if [ -f "$file" ]
to correctly handle empty strings or file names with spaces in them. With [[ the quotes are unnecessary:
if [[ -f $file ]]
Because it is a syntactical feature, it lets you use && and || operators for boolean tests and < and > for string comparisons. [ cannot do this because it is a regular command and &&, ||, <, and > are not passed to regular commands as command-line arguments.
It has a wonderful =~ operator for doing regular expression matches. With [ you might write
if [ "$answer" = y -o "$answer" = yes ]
With [[ you can write this as
if [[ $answer =~ ^y(es)?$ ]]
It even lets you access the captured groups which it stores in BASH_REMATCH. For instance, ${BASH_REMATCH[1]} would be "es" if you typed a full "yes" above.
You get pattern matching aka globbing for free. Maybe you're less strict about how to type yes. Maybe you're okay if the user types y-anything. Got you covered:
if [[ $ANSWER = y* ]]
Keep in mind that it is a bash extension, so if you are writing sh-compatible scripts then you need to stick with [. Make sure you have the #!/bin/bash shebang line for your script if you use double brackets.
See also
Bash FAQ - "What is the difference between test, [ and [[ ?"
Bash Practices - Bash Tests
Server Fault - What is the difference between double and single brackets in bash?
[ is the same as the test builtin, and works like the test binary (man test)
works about the same as [ in all the other sh-based shells in many UNIX-like environments
only supports a single condition. Multiple tests with the bash && and || operators must be in separate brackets.
doesn't natively support a 'not' operator. To invert a condition, use a ! outside the first bracket to use the shell's facility for inverting command return values.
== and != are literal string comparisons
[[ is a bash
is bash-specific, though others shells may have implemented similar constructs. Don't expect it in an old-school UNIX sh.
== and != apply bash pattern matching rules, see "Pattern Matching" in man bash
has a =~ regex match operator
allows use of parentheses and the !, &&, and || logical operators within the brackets to combine subexpressions
Aside from that, they're pretty similar -- most individual tests work identically between them, things only get interesting when you need to combine different tests with logical AND/OR/NOT operations.
The most important difference will be the clarity of your code. Yes, yes, what's been said above is true, but [[ ]] brings your code in line with what you would expect in high level languages, especially in regards to AND (&&), OR (||), and NOT (!) operators. Thus, when you move between systems and languages you will be able to interpret script faster which makes your life easier. Get the nitty gritty from a good UNIX/Linux reference. You may find some of the nitty gritty to be useful in certain circumstances, but you will always appreciate clear code! Which script fragment would you rather read? Even out of context, the first choice is easier to read and understand.
if [[ -d $newDir && -n $(echo $newDir | grep "^${webRootParent}") && -n $(echo $newDir | grep '/$') ]]; then ...
or
if [ -d "$newDir" -a -n "$(echo "$newDir" | grep "^${webRootParent}")" -a -n "$(echo "$newDir" | grep '/$')" ]; then ...
In bash, contrary to [, [[ prevents word splitting of variable values.

Resources