如何使用双括号或单括号,括号,花括号

我对Bash中括号、括号、花括号的用法以及它们的双括号和单括号的区别感到困惑。有明确的解释吗?

446035 次浏览
  1. 单个括号([)通常实际调用名为[的程序;man testman [以获取更多信息。示例:

    $ VARIABLE=abcdef$ if [ $VARIABLE == abcdef ] ; then echo yes ; else echo no ; fiyes
  2. The double bracket ([[) does the same thing (basically) as a single bracket, but is a bash builtin.

    $ VARIABLE=abcdef$ if [[ $VARIABLE == 123456 ]] ; then echo yes ; else echo no ; fino
  3. Parentheses (()) are used to create a subshell. For example:

    $ pwd/home/user$ (cd /tmp; pwd)/tmp$ pwd/home/user

    如您所见,子shell允许您在不影响当前shell环境的情况下执行操作。

  4. (a)大括号({})用于明确标识变量。示例:

    $ VARIABLE=abcdef$ echo Variable: $VARIABLEVariable: abcdef$ echo Variable: $VARIABLE123456Variable:$ echo Variable: ${VARIABLE}123456Variable: abcdef123456

    大括号还用于在当前 shell上下文中执行一系列命令,例如:

    $ { date; top -b -n1 | head ; } >logfile# 'date' and 'top' output are concatenated,# could be useful sometimes to hunt for a top loader )
    $ { date; make 2>&1; date; } | tee logfile# now we can calculate the duration of a build from the logfile

There is a subtle syntactic difference with ( ), though (see bash reference) ; essentially, a semicolon ; after the last command within braces is a must, and the braces {, } must be surrounded by spaces.

在Bash中,test[是shell内置的。

双括号是shell关键字,支持附加功能。例如,您可以使用&&||而不是-a-o,并且有一个正则表达式匹配运算符=~

此外,在一个简单的测试中,双方括号似乎比单方括号更快地评估。

$ time for ((i=0; i<10000000; i++)); do [[ "$i" = 1000 ]]; done
real    0m24.548suser    0m24.337ssys 0m0.036s$ time for ((i=0; i<10000000; i++)); do [ "$i" = 1000 ]; done
real    0m33.478suser    0m33.478ssys 0m0.000s

大括号,除了分隔变量名之外,还用于参数展开,因此您可以执行以下操作:

  • 截断变量的内容

    $ var="abcde"; echo ${var%d*}abc
  • Make substitutions similar to sed

    $ var="abcde"; echo ${var/de/12}abc12
  • Use a default value

    $ default="hello"; unset var; echo ${var:-$default}hello
  • and several more

Also, brace expansions create lists of strings which are typically iterated over in loops:

$ echo f{oo,ee,a}dfood feed fad
$ mv error.log{,.OLD}(error.log is renamed to error.log.OLD because the brace expressionexpands to "mv error.log error.log.OLD")
$ for num in {000..2}; do echo "$num"; done000001002
$ echo {00..8..2}00 02 04 06 08
$ echo {D..T..4}D H L P T

请注意,前导零和增量功能在Bash 4之前不可用。

感谢gboffi提醒我关于支撑扩展。

双括号用于算术运算

((a++))
((meaning = 42))
for ((i=0; i<10; i++))
echo $((a + b + (14 * c)))

它们使您能够省略整数和数组变量上的美元符号,并在运算符周围包含空格以提高易读性。

单括号也用于阵列索引:

array[4]="hello"
element=${array[index]}

右边的(大多数/全部?)数组引用需要花括号。

epheient的注释提醒我括号也用于子shell。它们用于创建数组。

array=(1 2 3)echo ${array[1]}2

我只是想从TLDP添加这些:

~:$ echo $SHELL/bin/bash
~:$ echo ${#SHELL}9
~:$ ARRAY=(one two three)
~:$ echo ${#ARRAY}3
~:$ echo ${TEST:-test}test
~:$ echo $TEST

~:$ export TEST=a_string
~:$ echo ${TEST:-test}a_string
~:$ echo ${TEST2:-$TEST}a_string
~:$ echo $TEST2

~:$ echo ${TEST2:=$TEST}a_string
~:$ echo $TEST2a_string
~:$ export STRING="thisisaverylongname"
~:$ echo ${STRING:4}isaverylongname
~:$ echo ${STRING:6:5}avery
~:$ echo ${ARRAY[*]}one two one three one four
~:$ echo ${ARRAY[*]#one}two three four
~:$ echo ${ARRAY[*]#t}one wo one hree one four
~:$ echo ${ARRAY[*]#t*}one wo one hree one four
~:$ echo ${ARRAY[*]##t*}one one one four
~:$ echo $STRINGthisisaverylongname
~:$ echo ${STRING%name}thisisaverylong
~:$ echo ${STRING/name/string}thisisaverylongstring

测试[[之间的区别在BashFAQ中有详细解释。(注:该链接显示了许多示例以供比较)

长话短说:test实现了旧的、可移植的语法命令。在几乎所有的炮弹中(最古老的Bourne炮弹是异常),[test的同义词(但需要])。尽管所有现代shell都内置了[的实现,通常仍然有一个该名称的外部可执行文件,例如。/bin/[.

[[是它的一个新的改进版本,它是一个关键字,而不是程序。这对易用性有有益的影响,如下所示。[[是被KornShell和BASH(例如2.03)理解,但不被旧的理解POSIX或BourneShell。

以及结论:

什么时候应该使用新的测试命令[[,什么时候使用旧的测试命令[?如果对POSIX或BourneShell的可移植性/一致性是一个问题,则旧语法应该被使用。另一方面,如果脚本需要BASH、Zsh或KornShell,新语法通常更灵活。

支架

if [ CONDITION ]    Test constructif [[ CONDITION ]]  Extended test constructArray[1]=element1   Array initialization[a-z]               Range of characters within a Regular Expression$[ expression ]     A non-standard & obsolete version of $(( expression )) [1]

[1]http://wiki.bash-hackers.org/scripting/obsolete

卷牙套

${variable}                             Parameter substitution${!variable}                            Indirect variable reference{ command1; command2; . . . commandN; } Block of code{string1,string2,string3,...}           Brace expansion{a..z}                                  Extended brace expansion{}                                      Text replacement, after find and xargs

括号

( command1; command2 )             Command group executed within a subshellArray=(element1 element2 element3) Array initializationresult=$(COMMAND)                  Command substitution, new style>(COMMAND)                         Process substitution<(COMMAND)                         Process substitution

双括号

(( var = 78 ))            Integer arithmeticvar=$(( 20 + 5 ))         Integer arithmetic, with variable assignment(( var++ ))               C-style variable increment(( var-- ))               C-style variable decrement(( var0 = var1<98?9:21 )) C-style ternary operation

函数定义中的括号

在函数定义中使用括号()

function_name () { command1 ; command2 ; }

这就是为什么即使在命令参数中也必须转义括号的原因:

$ echo (bash: syntax error near unexpected token `newline'
$ echo \((
$ echo () { command echo The command echo was redefined. ; }$ echo anythingThe command echo was redefined.
Truncate the contents of a variable
$ var="abcde"; echo ${var%d*}abc
Make substitutions similar to sed
$ var="abcde"; echo ${var/de/12}abc12
Use a default value
$ default="hello"; unset var; echo ${var:-$default}hello

关于如何使用括号分组和展开表达式的其他信息:
(它在链接语法括号上列出)

其中的一些要点:

子shell中的组命令:()
(列表)

当前shell中的组命令:{}
{list;}

测试-返回表达式的二进制结果: [[ ]]
[[表情]]

算术展开
算术展开的格式为:
$(表达式)

简单算术计算的格式是:
((表达式))

组合多个表达式
(表达式)
((expr1&&expr2))

括号、括号和大括号的一些常见和方便用法

如上所述,有时您希望显示消息而不会丢失返回值。这是一个方便的片段:

$ [ -f go.mod ] || { echo 'File not found' && false; }

如果文件go.mod存在于当前目录中,则不会产生输出和0(true)返回值。测试结果:

$ echo $?0

如果文件不存在,则会收到消息,但返回值为1(false),也可以测试:

$ [ -f fake_file ] || { echo 'File not found'; false; }File not found
$ echo $?1

您还可以简单地创建一个函数来检查文件是否存在:

fileexists() { [ -f "$1" ]; }

或者如果文件可读(未损坏、具有权限等):

canread() { [ -r "$1" ]; }

或者如果它是一个目录:

isdir() { [ -d "$1" ]; }

或者对于当前用户是可写的:

canwrite() { [ -w "$1" ]; }

或者如果文件存在且不为空(例如包含内容的日志文件…)

isempty() { [ -s "$1" ]; }

有更多的细节在:TLDP


您还可以查看路径上是否存在程序并且可用:

exists () { command -v $1 > /dev/null 2>&1; }

这在脚本中很有用,例如:

# gitit does an autosave commit to the current# if Git is installed and available.# If git is not available, it will use brew# (on macOS) to install it.## The first argument passed, if any, is used as# the commit message; otherwise the default is used.gitit() {$(exists git) && {git add --all;git commit -m "${1:-'GitBot: dev progress autosave'}";git push;} || brew install git;}