3793
Comment: lexicographically comparison IS possible with classic test, you just need to quote the operators
|
3546
clean up
|
Deletions are marked like this. | Additions are marked like this. |
Line 20: | Line 20: |
if [[ -e $file ]] | if [[ ! -e $file ]] |
Line 31: | Line 31: |
To cut a long story short: {{{[}}} implements the old, portable syntax of the command. Although all modern shells have built-in implementations, there usually still is an external executable of that name, e.g. {{{/bin/[}}}. {{{[[}}} is a new improved version of it, which is a keyword, not a program. This has beneficial effects on the ease of use, see below. {{{[[}}} is understood by KornShell, ["BASH"] (e.g. 2.03), KornShell93, and the ["POSIX"] shell, but not by the older BourneShell. | To cut a long story short: {{{[}}} implements the old, portable syntax of the command. Although all modern shells have built-in implementations, there usually still is an external executable of that name, e.g. {{{/bin/[}}}. {{{[[}}} is a new improved version of it, which is a keyword, not a program. This has beneficial effects on the ease of use, as shown below. {{{[[}}} is understood by KornShell and ["BASH"] (e.g. 2.03), but not by the older POSIX or BourneShell. |
Line 36: | Line 36: |
||<|4>string comparison||>||\>||-|| | ||<rowspan=4>string comparison||>||\>||-|| |
Line 38: | Line 38: |
||== (or =)||=||-|| | ||= (or ==)||=||-|| |
Line 40: | Line 40: |
||<|2>expression grouping||&&||-a||{{{[[ -n $var && -f $var ]] && echo "$var is a file"}}}|| | ||<rowspan=2>expression grouping||&&||-a||{{{[[ -n $var && -f $var ]] && echo "$var is a file"}}}|| |
Line 42: | Line 42: |
||Pattern matching||== (or =)||(not available)||{{{[[ $name = a* ]] || echo "name does not start with an 'a': $name"}}}|| ||In-process regular expression matching||=~||(not available)||{{{[[ $(date) =~ ^Fri\ ...\ 13 ]] && echo "It's Friday the 13th!"}}}|| |
||Pattern matching||= (or ==)||(not available)||{{{[[ $name = a* ]] || echo "name does not start with an 'a': $name"}}}|| ||RegularExpression matching||=~||(not available)||{{{[[ $(date) =~ ^Fri\ ...\ 13 ]] && echo "It's Friday the 13th!"}}}|| |
Line 54: | Line 54: |
* No field splitting will be done for {{{[[}}} (and therefore many arguments need not be quoted) | * No WordSplitting or [:glob:] expansion will be done for {{{[[}}} (and therefore many arguments need not be quoted): |
Line 67: | Line 67: |
* Parentheses in {{{[[}}} do not need to be escaped: {{{ [[ -f $file1 && ( -d $dir1 || -d $dir2) [ -f "$file1" -a \( -d "$dir1" -o -d "$dir2" \) ]}}} |
|
Line 68: | Line 72: |
* No file name generation will be done for {{{[[}}}. Therefore the following line tries to match the contents of the variable {{{$path}}} with the pattern {{{/*}}} | As a rule of thumb, {{{[[}}} is used for strings and files. If you want to compare numbers, use an ArithmeticExpression, e.g. |
Line 70: | Line 74: |
{{{ [[ $path = /* ]] && echo "\$path starts with a forward slash /: $path"}}} The next command most likely will result in an error, because {{{/*}}} is subject to file name generation: {{{ [ $path = /* ] && echo "this does not work"}}} (If you need to do that using Bourne shells, use {{{case}}} instead.) * As a rule of thumb, {{{[[}}} is used for strings and files. If you want to compare numbers, use an ArithmeticExpression, e.g. {{{ i=0 while ((i<10)); do ...}}} |
{{{ # Bash i=0 while ((i<10)); do ... }}} |
Line 87: | Line 81: |
See the [:BashGuide/Practices/BashTests:Bash Tests] chapter in the BashGuide. |
What is the difference between the old and new test commands ([ and [[)?
[ ("test" command) and [[ ("new test" command) are both used to evaluate expressions. Some examples:
if [ -z "$variable" ] then echo "variable is empty!" fi if [ ! -f "$filename" ] then echo "not a valid, existing file name: $filename" fi
and
if [[ ! -e $file ]] then echo "directory entry does not exist: $file" fi if [[ $file0 -nt $file1 ]] then echo "file $file0 is newer than $file1" fi
To cut a long story short: [ implements the old, portable syntax of the command. Although all modern shells have built-in implementations, there usually still is an external executable of that name, e.g. /bin/[. [[ is a new improved version of it, which is a keyword, not a program. This has beneficial effects on the ease of use, as shown below. [[ is understood by KornShell and ["BASH"] (e.g. 2.03), but not by the older POSIX or BourneShell.
Although [ and [[ have much in common, and share many expression operators like "-f", "-s", "-n", "-z", there are some notable differences. Here is a comparison list:
Feature |
new test [[ |
old test [ |
Example |
string comparison |
> |
\> |
- |
< |
\< |
- |
|
= (or ==) |
= |
- |
|
!= |
!= |
- |
|
expression grouping |
&& |
-a |
[[ -n $var && -f $var ]] && echo "$var is a file" |
|| |
-o |
- |
|
Pattern matching |
= (or ==) |
(not available) |
[[ $name = a* ]] || echo "name does not start with an 'a': $name" |
RegularExpression matching |
=~ |
(not available) |
[[ $(date) =~ ^Fri\ ...\ 13 ]] && echo "It's Friday the 13th!" |
Special primitives that [[ is defined to have, but [ may be lacking (depending on the implementation):
Description |
Primitive |
Example |
entry (file or directory) exists |
-e |
[[ -e $config ]] && echo "config file exists: $config" |
file is newer/older than other file |
-nt / -ot |
[[ $file0 -nt $file1 ]] && echo "$file0 is newer than $file1" |
two files are the same |
-ef |
[[ $input -ef $output ]] && { echo "will not overwrite input file: $input"; exit 1; } |
negation |
! |
- |
But there are more subtle differences.
No WordSplitting or [:glob:] expansion will be done for [[ (and therefore many arguments need not be quoted):
file="file name" [[ -f $file ]] && echo "$file is a file"
will work even though $file is not quoted and contains whitespace. With [ the variable needs to be quoted:
file="file name" [ -f "$file" ] && echo "$file is a file"
This makes [[ easier to use and less error-prone.
Parentheses in [[ do not need to be escaped:
[[ -f $file1 && ( -d $dir1 || -d $dir2) [ -f "$file1" -a \( -d "$dir1" -o -d "$dir2" \) ]
As a rule of thumb, [[ is used for strings and files. If you want to compare numbers, use an ArithmeticExpression, e.g.
# Bash i=0 while ((i<10)); do ...
When should the new test command [[ be used, and when the old one [? If portability to the BourneShell is a concern, the old syntax should be used. If on the other hand the script requires ["BASH"] or KornShell, the new syntax is much more flexible.
See the [:BashGuide/Practices/BashTests:Bash Tests] chapter in the BashGuide.