请问 if [[ -f $(which stardict) ]] 中的 [[ ]] 是什么意思?
test 不是用[ ] 代替的吗?
请问 if [[ -f $(which stardict) ]] 中的 [[ ]] 是什么意思?test =[ ]
-
- 帖子: 3
- 注册时间: 2006-09-15 15:49
- eexpress
- 帖子: 58428
- 注册时间: 2005-08-14 21:55
- 来自: 长沙
-
- 帖子: 3
- 注册时间: 2006-09-15 15:49
- iblicf
- 帖子: 3766
- 注册时间: 2007-01-15 17:15
iblicf@ubuntu:~$ type '['
[ is a shell builtin
iblicf@ubuntu:~$ type '[['
[[ is a shell keyword
iblicf@ubuntu:~$
LOOK-->《高级Bash脚本编程指南》[3.7版本]
[ is a shell builtin
iblicf@ubuntu:~$ type '[['
[[ is a shell keyword
iblicf@ubuntu:~$
LOOK-->《高级Bash脚本编程指南》[3.7版本]
-
- 帖子: 3
- 注册时间: 2006-09-15 15:49
网上找到一段讨论,看得有点晕
---------------------------------------------------
woodie 回复于:2005-12-26 16:17:07
1. 首先,尽管很相似,但是从概念上讲,二者是不同层次的东西。
"[[",是关键字,许多shell(如ash bsh)并不支持这种方式。ksh, bash(据说从2.02起引入对[[的支持)等支持。
"["是一条命令, 与test等价,大多数shell都支持。在现代的大多数sh实现中,"["与"test"是内部(builtin)命令,换句话说执行"test"/"["时不会调用/some/path/to/test这样的外部命令(如果有这样的命令的话)。
下面是在rh7.3下的测试结果,GNU bash, version 2.05a.0(1),安装了sh-utils。
$ type test
test is a shell builtin
$ type [
[ is a shell builtin
$ rpm -ql sh-utils|grep test
/usr/bin/test
/usr/share/man/man1/test.1.gz
$ ls -l `which test`
-rwxr-xr-x 1 root root 20424 4月 9 2002 /usr/bin/test
ls -l $(which [)
lrwxrwxrwx 1 root root 4 8月 23 2002 /usr/bin/[ -> test
在你的机器上结果可能会有所不同哦。
2. 相同的地方是二者都支持算术比较和字符串比较表达式。
举例(测试环境bash 2.05b.0(1),下同):
$ [ 2 -lt 10 ]&&echo true&&echo false
true
$ [ 2 -gt 10 ]&&echo true||echo false
false
$ [ 2 \< 10 ]&&echo true||echo false #you should use "\<"
false
$ [ 2 \> 10 ]&&echo true||echo false #you should use "\>"
true
$ [[ 2 -gt 10 ]]&&echo true||echo false
false
$ [[ 2 -lt 10 ]]&&echo true||echo false
true
$ [[ 2 < 10 ]]&&echo true||echo false
false
$ [[ 2 > 10 ]]&&echo true||echo false
true
$ [ test = test ]&&echo true||echo false #normal compare
true
$ [ test = t*t ]&&echo true||echo false #pattern match.
true
$ [ test = t..t ]&&echo true||echo false #not match.
false
$ [ test = t??t ]&&echo true||echo false #note that "?", not "." stands for one single character here
true
$ [ test = "t??t" ]&&echo true||echo false #alert: don't quote the pattern
false
$ [[ test = test ]]&&echo true||echo false #normal compare
true
$ [[ test = t*t ]]&&echo true||echo false #pattern match.
true
$ [[ test = t..t ]]&&echo true||echo false #not match.
false
$ [[ test = t??t ]]&&echo true||echo false #note that "?", not "." stands for one single character here
true
$ [[ test = "t??t" ]]&&echo true||echo false #alert: don't quote the pattern
false
说明:
"-gt", "-lt"是算术比较操作符,用于比较整数的大小。
">", "<"是字符串比较操作符,用于比较字符串的大小,使用字典顺序,与当前的locale有关。
另外,"="还可以做简单的模式匹配,与一般的正则表达式不同,这里的模式匹配要简单得多,类似文件名的统配符的扩展规则。还要注意等号右端的模式不能用引号括起。
第2点是谈相同点,以下的都是二者"行为上"的不同点。
3. [[的行为相对地更接近于其他语言,例如"&&"而不是"-a"表示逻辑"与",用"||"而不是"-o"表示逻辑"或"。
例如:
$ [[ 1 < 2 && b > a ]]&&echo true||echo false
true
$ [[ 1 < 2 -a b > a ]]&&echo true||echo false
bash: syntax error in conditional expression
bash: syntax error near `-a'
$ [ 1 < 2 -a b > a ]&&echo true||echo false
true
$ [ 1 < 2 && b > a ]&&echo true||echo false #wrong syntax
bash: [: missing `]'
false
$ [ 1 < 2 \&\& b > a ]&&echo true||echo false #aslo wrong
bash: [: &&: binary operator expected
false
4. [ ... ]为shell命令,所以在其中的表达式应是它的命令行参数,所以串比较操作符">" 与"<"必须转义,否则就变成IO改向操作符了(请参看上面2中的例子)。在[[中"<"与">"不需转义;
由于"[["是关键字,不会做命令行扩展,因而相对的语法就稍严格些。例如
在[ ... ]中可以用引号括起操作符,因为在做命令行扩展时会去掉这些引号,而在[[ ... ]]则不允许这样做。
举例:
$ [ "-z" "" ]&&echo true||echo false
true
$ [ -z "" ]&&echo true||echo false
true
$ [[ "-z" "" ]]&&echo true||echo false
bash: conditional binary operator expected
bash: syntax error near `""'
$ [[ -z "" ]]&&echo true||echo false
true
5. [[ ... ]]进行算术扩展,而[ ... ]不做。
举例:
$ [[ 99+1 -eq 100 ]]&&echo true||echo false
true
$ [ 99+1 -eq 100 ]&&echo true||echo false
bash: [: 99+1: integer expression expected
false
$ [ $((99+1)) -eq 100 ]&&echo true||echo false
true
----------
woodie 回复于:2005-12-26 16:21:11
shaoping0330的钻研精神让人佩服。我再补充几点:
1.((...))等价于let,专门用来进行算术运算、比较,bsh中也可以使用,而且最妙的是它支持C风格的运算符。要取得算术表达式的值时可以用"$((expression))"形式
举例:
$ ((i=1+99)) ; echo $i
100
$ echo $((i++))
101
$ echo $((--i))
100
$ echo $((2**3))
8
$ echo $((5%3))
2
$ echo $((1<2?10:20))
10
2.test等价于[],与[[]]相似但有些区别;既可用于算术运算、比较又可用于字符串、文件测试。算术比较用 -eq, -lt, -gt, -le, -ge,字符串比较用<, >, =, !=, >=和<=这两个是无效的。[]中逻辑运算用:-a, -o,而[[中用&&, ||;[[不能用于bsh,但可用在ksh/bash/zsh中。
3.正如我在以前的帖子中指出的,可以把[...]看作一个shell命令,方括号中的内容就是命令行参数。所以"<"、">"并不是不可以用在[...]中,只不过他们是shell的"元字符",使用前必须用"\"转义,去掉其特殊含义就可以了。
4.关于字符串比较。[...]、[[...]]中都可以对字符串进行比较,比较的顺序是"字典顺序"。对ascii字符来讲,码表中排列在前的较小,如A<B,A<a, 1<2。再强调一次,这里只要用了"<"、">",就表示是字符串比较,那么9 > 100为真,因为这实际上等价于‘9’ > ‘100’,9在码表中排在1后面,所以字符串"9"大于字符串"100"。只要搞清楚了何时是算术比较,何时是串比较,一般就不会出错了。至于不要使用"<"、">"的意见,我不能苟同。:)
5.((...))的结构对于算术运算应该大力提倡,这一点我非常赞成。
6.shaoping说[[在bash与ksh中不同,是指什么?请指教。我对ksh不是很熟。:-(
woodie 回复于:2005-12-26 16:24:36
>相比较而言,使用 [[ ]] 比使用 [ ] 更可靠,建议多多使用。
我的意见两者都是可靠的,尽可以大胆使用。实际上[]的兼容性更好些,因为在bsh这样古老的shell中也能使用;[[]]则只能用于ksh及其后继者bash、zsh中。
>不过woodie兄台所提到的第 4 点 是有些遗漏的,在 [ ]中若直接使用 > < 其结果会很迷惑的。
看来shaoping兄还是没搞清楚,大概是我前面都没写清楚吧。:)
"<"和">"可以直接用在[[]]中。但不可以直接用在[]中,只能加"\"转义后或者用引号括起后使用,否则shell就会把它解释为输入输出改向符。
看例子:
$ ls 200?
ls: 200?: No such file or directory
$ [ 2004 < 2005 ]
bash: 2005: No such file or directory
$ echo $?
1
$ [ 2004 > 2005 ]
$ echo $?
0
$ ls 200?
2005
首先列一下目录,保证没有200?字样的文件存在。
然后执行[ 2004 < 2005 ],shell试图对文件2005作标准输入,但无法找到文件2005。
执行[ 2004 > 2005 ],系统正常执行了命令。
再列下目录,已经生成了文件2005!
再看:
$ [ 2004 "<" 2006 ]&&echo true||echo false
true
$ [ 2004 '>' 2006 ]&&echo true||echo false
false
$ [ 2004 \> 2006 ]&&echo true||echo false
false
看到了吧,去掉了特殊含义的"<"和">"就表现得规规矩矩的了。:)
---------------------------------------------------
woodie 回复于:2005-12-26 16:17:07
1. 首先,尽管很相似,但是从概念上讲,二者是不同层次的东西。
"[[",是关键字,许多shell(如ash bsh)并不支持这种方式。ksh, bash(据说从2.02起引入对[[的支持)等支持。
"["是一条命令, 与test等价,大多数shell都支持。在现代的大多数sh实现中,"["与"test"是内部(builtin)命令,换句话说执行"test"/"["时不会调用/some/path/to/test这样的外部命令(如果有这样的命令的话)。
下面是在rh7.3下的测试结果,GNU bash, version 2.05a.0(1),安装了sh-utils。
$ type test
test is a shell builtin
$ type [
[ is a shell builtin
$ rpm -ql sh-utils|grep test
/usr/bin/test
/usr/share/man/man1/test.1.gz
$ ls -l `which test`
-rwxr-xr-x 1 root root 20424 4月 9 2002 /usr/bin/test
ls -l $(which [)
lrwxrwxrwx 1 root root 4 8月 23 2002 /usr/bin/[ -> test
在你的机器上结果可能会有所不同哦。
2. 相同的地方是二者都支持算术比较和字符串比较表达式。
举例(测试环境bash 2.05b.0(1),下同):
$ [ 2 -lt 10 ]&&echo true&&echo false
true
$ [ 2 -gt 10 ]&&echo true||echo false
false
$ [ 2 \< 10 ]&&echo true||echo false #you should use "\<"
false
$ [ 2 \> 10 ]&&echo true||echo false #you should use "\>"
true
$ [[ 2 -gt 10 ]]&&echo true||echo false
false
$ [[ 2 -lt 10 ]]&&echo true||echo false
true
$ [[ 2 < 10 ]]&&echo true||echo false
false
$ [[ 2 > 10 ]]&&echo true||echo false
true
$ [ test = test ]&&echo true||echo false #normal compare
true
$ [ test = t*t ]&&echo true||echo false #pattern match.
true
$ [ test = t..t ]&&echo true||echo false #not match.
false
$ [ test = t??t ]&&echo true||echo false #note that "?", not "." stands for one single character here
true
$ [ test = "t??t" ]&&echo true||echo false #alert: don't quote the pattern
false
$ [[ test = test ]]&&echo true||echo false #normal compare
true
$ [[ test = t*t ]]&&echo true||echo false #pattern match.
true
$ [[ test = t..t ]]&&echo true||echo false #not match.
false
$ [[ test = t??t ]]&&echo true||echo false #note that "?", not "." stands for one single character here
true
$ [[ test = "t??t" ]]&&echo true||echo false #alert: don't quote the pattern
false
说明:
"-gt", "-lt"是算术比较操作符,用于比较整数的大小。
">", "<"是字符串比较操作符,用于比较字符串的大小,使用字典顺序,与当前的locale有关。
另外,"="还可以做简单的模式匹配,与一般的正则表达式不同,这里的模式匹配要简单得多,类似文件名的统配符的扩展规则。还要注意等号右端的模式不能用引号括起。
第2点是谈相同点,以下的都是二者"行为上"的不同点。
3. [[的行为相对地更接近于其他语言,例如"&&"而不是"-a"表示逻辑"与",用"||"而不是"-o"表示逻辑"或"。
例如:
$ [[ 1 < 2 && b > a ]]&&echo true||echo false
true
$ [[ 1 < 2 -a b > a ]]&&echo true||echo false
bash: syntax error in conditional expression
bash: syntax error near `-a'
$ [ 1 < 2 -a b > a ]&&echo true||echo false
true
$ [ 1 < 2 && b > a ]&&echo true||echo false #wrong syntax
bash: [: missing `]'
false
$ [ 1 < 2 \&\& b > a ]&&echo true||echo false #aslo wrong
bash: [: &&: binary operator expected
false
4. [ ... ]为shell命令,所以在其中的表达式应是它的命令行参数,所以串比较操作符">" 与"<"必须转义,否则就变成IO改向操作符了(请参看上面2中的例子)。在[[中"<"与">"不需转义;
由于"[["是关键字,不会做命令行扩展,因而相对的语法就稍严格些。例如
在[ ... ]中可以用引号括起操作符,因为在做命令行扩展时会去掉这些引号,而在[[ ... ]]则不允许这样做。
举例:
$ [ "-z" "" ]&&echo true||echo false
true
$ [ -z "" ]&&echo true||echo false
true
$ [[ "-z" "" ]]&&echo true||echo false
bash: conditional binary operator expected
bash: syntax error near `""'
$ [[ -z "" ]]&&echo true||echo false
true
5. [[ ... ]]进行算术扩展,而[ ... ]不做。
举例:
$ [[ 99+1 -eq 100 ]]&&echo true||echo false
true
$ [ 99+1 -eq 100 ]&&echo true||echo false
bash: [: 99+1: integer expression expected
false
$ [ $((99+1)) -eq 100 ]&&echo true||echo false
true
----------
woodie 回复于:2005-12-26 16:21:11
shaoping0330的钻研精神让人佩服。我再补充几点:
1.((...))等价于let,专门用来进行算术运算、比较,bsh中也可以使用,而且最妙的是它支持C风格的运算符。要取得算术表达式的值时可以用"$((expression))"形式
举例:
$ ((i=1+99)) ; echo $i
100
$ echo $((i++))
101
$ echo $((--i))
100
$ echo $((2**3))
8
$ echo $((5%3))
2
$ echo $((1<2?10:20))
10
2.test等价于[],与[[]]相似但有些区别;既可用于算术运算、比较又可用于字符串、文件测试。算术比较用 -eq, -lt, -gt, -le, -ge,字符串比较用<, >, =, !=, >=和<=这两个是无效的。[]中逻辑运算用:-a, -o,而[[中用&&, ||;[[不能用于bsh,但可用在ksh/bash/zsh中。
3.正如我在以前的帖子中指出的,可以把[...]看作一个shell命令,方括号中的内容就是命令行参数。所以"<"、">"并不是不可以用在[...]中,只不过他们是shell的"元字符",使用前必须用"\"转义,去掉其特殊含义就可以了。
4.关于字符串比较。[...]、[[...]]中都可以对字符串进行比较,比较的顺序是"字典顺序"。对ascii字符来讲,码表中排列在前的较小,如A<B,A<a, 1<2。再强调一次,这里只要用了"<"、">",就表示是字符串比较,那么9 > 100为真,因为这实际上等价于‘9’ > ‘100’,9在码表中排在1后面,所以字符串"9"大于字符串"100"。只要搞清楚了何时是算术比较,何时是串比较,一般就不会出错了。至于不要使用"<"、">"的意见,我不能苟同。:)
5.((...))的结构对于算术运算应该大力提倡,这一点我非常赞成。
6.shaoping说[[在bash与ksh中不同,是指什么?请指教。我对ksh不是很熟。:-(
woodie 回复于:2005-12-26 16:24:36
>相比较而言,使用 [[ ]] 比使用 [ ] 更可靠,建议多多使用。
我的意见两者都是可靠的,尽可以大胆使用。实际上[]的兼容性更好些,因为在bsh这样古老的shell中也能使用;[[]]则只能用于ksh及其后继者bash、zsh中。
>不过woodie兄台所提到的第 4 点 是有些遗漏的,在 [ ]中若直接使用 > < 其结果会很迷惑的。
看来shaoping兄还是没搞清楚,大概是我前面都没写清楚吧。:)
"<"和">"可以直接用在[[]]中。但不可以直接用在[]中,只能加"\"转义后或者用引号括起后使用,否则shell就会把它解释为输入输出改向符。
看例子:
$ ls 200?
ls: 200?: No such file or directory
$ [ 2004 < 2005 ]
bash: 2005: No such file or directory
$ echo $?
1
$ [ 2004 > 2005 ]
$ echo $?
0
$ ls 200?
2005
首先列一下目录,保证没有200?字样的文件存在。
然后执行[ 2004 < 2005 ],shell试图对文件2005作标准输入,但无法找到文件2005。
执行[ 2004 > 2005 ],系统正常执行了命令。
再列下目录,已经生成了文件2005!
再看:
$ [ 2004 "<" 2006 ]&&echo true||echo false
true
$ [ 2004 '>' 2006 ]&&echo true||echo false
false
$ [ 2004 \> 2006 ]&&echo true||echo false
false
看到了吧,去掉了特殊含义的"<"和">"就表现得规规矩矩的了。:)