[[ , [ , ( , ((
我见过人们在这样的if语句上使用它们:
if [[condition]]
if [condition]
if ((condition))
if (condition)
#1 楼
在类似Bourne的shell中,如果if
命令列表的退出代码为零,则then
语句通常看起来像if
command-list1
then
command-list2
else
command-list3
fi
执行
command-list1
子句。如果退出代码为非零,则执行else
子句。 command-list1
可以是简单的也可以是复杂的。例如,它可以是由一个运算符;
,&
,&&
,||
或换行符之一分隔的一个或多个管道的序列。下面显示的if
条件只是command-list1
的特例:if [ condition ]
[
是传统test
命令的另一个名称。 [
/ test
是标准的POSIX实用程序。所有POSIX外壳程序都内置了它(尽管POSIX²不需要)。 test
命令设置退出代码,并且if
语句相应地起作用。典型的测试是文件是否存在或一个数字是否等于另一个数字。if [[ condition ]]
这是ksh对
test
¹的新升级版本,其中bash,zsh,yash, busybox sh也支持。此[[ ... ]]
构造还设置了退出代码,并且if
语句相应地起作用。在其扩展功能中,它可以测试字符串是否匹配通配符模式(不在busybox sh中)。if ((condition))
bash和zsh也支持的另一个ksh扩展。这执行算术运算。算术的结果是,设置了退出代码,并且
if
语句相应地起作用。如果算术计算的结果为非零,则返回零(真)的退出码。像[[...]]
一样,此格式也不是POSIX,因此也不是可移植的。if (command)
这在子shell中运行命令。命令完成后,它将设置退出代码,并且
if
语句将相应地执行操作。使用此类子外壳的典型原因是,如果
command
需要对外壳环境进行变量分配或其他更改,则可以限制command
的副作用。子外壳程序完成后,此类更改不会保留。if command
命令已执行,并且
if
语句根据其退出代码执行操作。¹虽然不是真正的命令,但是是一种特殊的shell构造,其语法与普通命令的语法不同,并且在shell实现之间存在很大差异。
POSIX确实需要有一个独立的
test
和但是,系统上的[
实用程序,尽管对于[
来说,已知有多个Linux发行版缺少它。评论
感谢您加入第5个选项。这是了解其实际工作方式以及未得到充分利用的关键。
–小鸡
16年8月30日在19:32
请注意[实际上是二进制文件,而不是内部命令或符号。通常居住在/ bin中。
–朱利安·R。
16-09-3在12:17
@JulienR。实际上[是内置的,测试也是。由于兼容性原因,有二进制版本可用。查看帮助[并进行测试。
– OldTimer
16-09-20在4:23
值得注意的是,虽然(((is POSIX,$((即算术扩展是,很容易混淆它们。通常,一种解决方法是使用[$((2 + 2))-eq 4]之类的东西)情节陈述
– Sergiy Kolodyazhnyy
17年11月30日在18:10
我希望我可以多次投票赞成这个答案。完美的解释。
–安东尼·加特林
19-10-9在11:33
#2 楼
(…)
括号表示一个子外壳。它们里面的东西并不像许多其他语言那样表达。这是命令列表(就像外括号一样)。这些命令在单独的子过程中执行,因此括号内执行的任何重定向,赋值等在括号外均无效。带有前导美元符号的
$(…)
是命令替换:括号内有一个命令,命令的输出用作命令行的一部分(额外扩展后,除非替换在双引号之间,但这是另一回事)。{ … }
大括号就像括号一样,因为它们将命令分组,但是它们仅影响语法分析,而不影响分组。程序x=2; { x=4; }; echo $x
打印4,而x=2; (x=4); echo $x
打印2。(另外,括号也需要定界,并在命令位置找到(因此,在{
之后的空间和;
之前的}
的空间),而括号没有。这只是一个语法怪异。) ${VAR}
具有前导美元符号,是一种参数扩展,可以扩展为变量的值,并可能进行其他转换。 ksh93
外壳程序还支持${ cmd;}
作为命令替换的形式,该命令替换形式不会生成子shell。((…))
双括号括在算术指令周围,即对整数进行计算,其语法类似于其他编程语言。此语法主要用于赋值和条件句中。仅在ksh / bash / zsh中存在,而在普通sh中不存在。算术表达式
$((…))
使用相同的语法,该语法扩展为表达式的整数值。 > [ … ]
单括号括起来的条件表达式。条件表达式主要建立在诸如-n "$variable"
之类的运算符上,以测试变量是否为空,而-e "$file"
则用于测试文件是否存在。请注意,您需要在每个运算符周围留一个空格(例如[ "$x" = "$y" ]
而不是[ "$x"="$y" ]
),并且在括号内外都需要一个空格或类似;
的字符(例如[ -n "$foo" ]
而不是[-n "$foo"]
)。 [[ … ]]
双括号是ksh / bash / zsh中条件表达式的替代形式,具有一些附加功能,例如,您可以编写[[ -L $file && -f $file ]]
来测试文件是否是指向常规文件的符号链接,而单括号要求[ -L "$file" ] && [ -f "$file" ]
。请参见为什么用带引号的空格进行参数扩展在双括号[[而不是单括号[?有关此主题的更多信息。在shell中,每个命令都是条件命令:每个命令的返回状态均为0表示成功或1到255之间的整数(在某些情况下可能更多)外壳)表示失败。
[ … ]
命令(或[[ … ]]
语法形式)是一个特殊命令,也可以拼写为test …
并在文件存在或字符串为非空或数字小于另一个时成功执行,等等。当数字非零时成功。以下是一些Shell脚本中的条件语句示例:测试
((…))
是否包含字符串myfile
:if grep -q hello myfile; then …
如果
hello
是目录,请切换到该目录并执行以下操作:if cd mydir; then
echo "Creating mydir/myfile"
echo 'some content' >myfile
else
echo >&2 "Fatal error. This script requires mydir to exist."
fi
测试是否存在一个名为
mydir
的文件当前目录:if [ -e myfile ]; then …
相同,但还包括悬挂的符号链接:
if [ -e myfile ] || [ -L myfile ]; then …
测试
myfile
(假定为数字)的值是否至少为2,可移植:if [ "$x" -ge 2 ]; then …
在bash / ksh / zsh中测试
x
(假定为数字)的值是否至少为2:if ((x >= 2)); then …
评论
请注意,单括号支持-a而不是&&,因此可以编写:[-L $ file -a -f $ file],该括号内的字符数相同,而没有多余的[和] ...
– Alexis Wilke
16年8月27日在23:34
@AlexisWilke运算符-a和-o存在问题,因为如果涉及的某些操作数看起来像运算符,则它们可能导致错误的解析。这就是为什么我没有提到它们:它们的优势为零,而且并不总是有效。而且也不要在没有充分理由的情况下写未加引号的变量扩展名:[[-L $ file -a -f $ file]]很好,但是需要使用单括号,[-L“ $ file” -a -f“ $ file”](可以,例如$ file始终以/或./开头。
–吉尔斯'所以-不再是邪恶的'
16-8-27在23:38
请注意,它是[[-L $ file && -f $ file]](不带[[...]]变体的-a)。
–StéphaneChazelas
17年11月30日在15:25
#3 楼
[
vs [[
此答案将涵盖问题的
[
vs [[
子集。Bash 4.3.11上的某些区别:
POSIX vs Bash扩展:
[
是POSIX [[
是Bash扩展¹,记录在: https://www.gnu.org/software/bash/manual/bash.html#Conditional-Constructs 常规命令vs魔术
[
只是一个具有奇怪名称的常规命令。]
只是[
的自变量,可以防止使用其他自变量。 > Ubuntu 16.04实际上在coreutils提供的
/usr/bin/[
处有一个可执行文件,但是bash内置版本优先。Bash解析命令的方式没有改变。
特别地,
<
是重定向的,&&
和||
连接多个命令,( )
生成子shell除非es以\
为上限,并且单词扩展照常进行。[[ X ]]
是使X
能够被神奇地解析的单个结构。 <
,&&
,||
和()
经过特殊处理,并且分词规则不同。还有进一步的区别,例如
=
和=~
。内置命令,并且[
是关键字:https://askubuntu.com/questions/445749/whats-the-difference-between-shell-builtin-and-shell-keyword [[
<
:字典比较[[ a < b ]]
:与上述相同。 [ a \< b ]
是必需的,否则像其他任何命令一样进行重定向。 Bash扩展。\
:等效POSIX²,请参见:https://stackoverflow.com/questions/21294867/how-to-test-strings-for-lexicographic-less-than-or-equal- in-bash / 52707989#52707989 expr a \< b > /dev/null
和&&
||
:真,逻辑和[[ a = a && b = b ]]
:语法错误,[ a = a && b = b ]
被解析为AND命令分隔符&&
cmd1 && cmd2
:等效,但已被POSIX³弃用。[ a = a -a b = b ]
:POSIX和可靠的等效物>
[ a = a ] && [ b = b ]
:假(
:语法错误,[[ (a = a || a = b) && a = b ]]
被解释为子外壳POSIX不推荐使用[ ( a = a ) ]
POSIX等效5 扩展时拆分单词和生成文件名(split + glob)
()
:true,不需要引号[ \( a = a -o a = b \) -a a = b ]
:语法错误,扩展为()
{ [ a = a ] || [ a = b ]; } && [ a = b ]
:语法如果当前目录中有多个文件,则会发生错误。x='a b'; [[ $x = 'a b' ]]
:等效于POSIX的x='a b'; [ $x = 'a b' ]
[ a b = 'a b' ]
:正确,因为它可以进行模式匹配(x='*'; [ $x = 'a b' ]
很神奇)。不会将glob扩展到当前目录中的文件。x='a b'; [ "$x" = 'a b' ]
:=
glob会扩展。因此,根据当前目录中的文件,可能是true还是false。[[ ab = a? ]]
:false,不是全局扩展但是* ? [
是Bash扩展名。 [ ab = a? ]
a?
:正确,POSIX扩展正则表达式匹配,[ ab = a\? ]
不全局扩展=
:语法错误。没有bash等效项。==
:等效于POSIX(仅单行数据)[
:等效于POSIX。 >建议:请始终使用[[
。我见过的每个
==
构造都有POSIX等效项。如果使用
case ab in (a?) echo match; esac
,则:可移植性差
迫使读者学习另一个bash扩展的复杂性。
[[ ab =~ 'ab?' ]]
只是一个具有奇怪名称的常规命令,不涉及任何特殊的语义。¹源自Korn shell中等效的
''
构造²,但对于
[[ ab? =~ 'ab?' ]]
或=~
的某些值(例如[[ ab =~ ab? ]]
或?
)失败,并且如果[ a =~ a ]
和printf 'ab\n' | grep -Eq 'ab?'
看起来像十进制整数,则进行数值比较。 awk 'BEGIN{exit !(ARGV[1] ~ ARGV[2])}' ab 'ab?'
可以同时解决这两个问题。³,并且对于某些
[]
或[[ ]]
值(如[[ ]]
或[
)也失败。没有启用(例如[[...]]
)5,尽管不需要分组(这里使用
a
命令组而不是b
,它将运行不必要的子shell),因为+
和index
shell运算符(相对于a
和b
,expr "x$a" '<' "x$b"
运算符或a
/ b
,!
运算符)具有相同的优先级。因此,(
等效。评论
@StéphaneChazelas感谢您的信息!我已经将expr添加到了答案。术语“ Bash扩展”并不意味着Bash是第一个添加一些语法的Shell,学习POSIX sh vs Bash已经足以使我发疯。
– Ciro Santilli郝海东冠状病六四事件法轮功
19年2月5日,9:11
如果尝试过男人[并且迷路了,请参见man test。这将解释POSIX变体。
–乔纳森·科玛(Jonathan Komar)
19年4月4日在7:25
#4 楼
从bash文档中:(list)
列表在子shell环境中执行(请参阅下面的COMMAND EXECUTION ENVIRONMENT)。在命令完成后,影响外壳环境的变量分配和内置命令将保持无效。返回状态是list的退出状态。换句话说,您要确保'list'中发生的任何事情(例如
cd
)在(
和)
之外均无效。唯一会泄漏的是最后一个命令的退出代码,或者与set -e
一起生成错误的第一个命令(除了少数几个,例如if
,while
等)。((expression))
根据以下算术评估中所述的规则评估表达式。如果表达式的值不为零,则返回状态为0;否则,返回状态为0。否则返回状态为1。这完全等同于让“表达式”。这是一个bash扩展,允许您进行数学运算。这与使用
expr
有点类似,但没有expr
的所有限制(例如到处都有空格,转义*
等)。[[ expression ]]
根据评估返回状态0或1条件表达式的表达式。表达式由以下条件表达式中描述的基元组成。不对[[和]]之间的单词进行单词拆分和路径名扩展;执行波浪号扩展,参数和变量扩展,算术扩展,命令替换,进程替换和引用删除。条件运算符(例如-f)必须不加引号,才能将其识别为基数。 br />此功能提供了高级测试,可以比较字符串,数字和文件,类似于test
所提供的功能,但功能更强大。[ expr ]
根据条件表达式expr的计算结果返回状态0(真)或1(假)。每个运算符和oper都必须是一个单独的参数。表达式由上面在条件表达式下描述的基元组成。测试不接受任何选项,也不接受-忽略-的参数表示选项的结尾。[...]
这个叫
test
。实际上,在过去,[
是到test
的符号链接。它的工作方式相同,您也有相同的限制。由于二进制文件知道启动它的名称,因此测试程序可以解析参数,直到找到参数]
为止。有趣的Unix技巧。请注意,在
bash
的情况下,[
和test
是内置函数(如注释中所述),但是存在几乎相同的限制。评论
尽管test和[当然是Bash中的内置命令,但是很可能也存在一个外部二进制文件。
–ilkkachu
16年8月27日在19:12
[的外部二进制文件不是在大多数现代系统上进行测试的符号链接。
–Random832
16年8月27日在19:16
不知何故,我发现它们烦恼地创建两个单独的二进制文件,这两个二进制文件恰好具有它们所需要的,而不是仅仅组合它们并添加了一些条件。尽管实际上/ usr / bin / test字符串显示它也具有帮助文本,所以我不知道该说些什么。
–ilkkachu
16年8月27日在19:50
@ Random832我对GNU的基本原理可以避免意外的arg0行为,但对于POSIX要求,我不是很肯定。虽然标准显然要求test命令作为基于独立文件的命令存在,但其中没有任何内容表明它的变体也需要以这种方式实现。例如,Solaris 11不提供任何可执行文件,但仍完全符合POSIX标准
– jlliagre
16-8-28的4:00
(出口1)在括号之外有作用。
–亚历山大
18年10月10日在8:23
#5 楼
某些示例:传统测试:
foo="some thing"
# check if value of foo is not empty
if [ -n "$foo" ] ; then...
if test -n "$foo" ; then...
test
和[
是与其他命令一样的命令,因此,除非将变量放在其中,否则将其拆分为单词引号。 新型测试
[[ ... ]]
是一种(较新的)特殊的shell构造,其工作方式略有不同,最明显的是它没有单词拆分变量:if [[ -n $foo ]] ; then...
此处有关
[
和[[
的一些文档。算术测试:
foo=12 bar=3
if (( $foo + $bar == 15 )) ; then ...
“普通”命令:
以上所有内容都像普通命令一样,并且
if
可以接受任何命令:# grep returns true if it finds something
if grep pattern file ; then ...
多个命令:
或者我们可以使用多个命令。在
( ... )
中包装一组命令会在子shell中运行它们,从而创建shell状态(工作目录,变量)的临时副本。如果我们需要暂时在另一个目录中运行某些程序,请执行以下操作:# this will move to $somedir only for the duration of the subshell
if ( cd $somedir ; some_test ) ; then ...
# while here, the rest of the script will see the new working
# directory, even after the test
if cd $somedir ; some_test ; then ...
#6 楼
将命令分组Bash提供了两种将要作为单元执行的命令列表分组的方法。
( list )
将命令列表放在括号之间会导致创建子外壳环境,以及列表中要在该子Shell中执行的每个命令。由于该列表是在子Shell中执行的,因此变量赋值在子Shell完成后不会保持有效。。没有创建子外壳。以下列表是分号(或换行符)。来源
$ a=1; (a=2; echo "inside: a=$a"); echo "outside: a=$a"
inside: a=2
outside: a=1
条件构造
单括号,即
{ list; }
为了比较
[]
和==, !=, <,
,应使用>
和eq, ne,lt
进行数值比较。增强的括号,即
gt
在以上所有示例中,我们仅使用单括号将条件表达式括起来,但是bash允许使用双括号,这是单括号语法的增强版本。
对于比较
[[]]
和==, !=, <,
可以直接使用。>
是test命令的同义词。即使将其内置到外壳中,它也会创建一个新进程。[
是它的新改进版本,它是关键字,而不是程序。[[
被[[
和Korn
理解。来源
评论
相关:使用单括号或双括号– bash括号和方括号在文档中不太容易搜索,如果您不知道这些功能的名称,那么便拥有这些。