什么时候在bash中使用()和{}?


Answers:


87

如果要使命令列表的副作用影响当前的 shell,请使用{...}
如果要放弃任何副作用,请使用(...)

例如,如果我:

  • 想更改$IFS一些命令,但我不想$IFS为当前外壳全局更改
  • cd某个地方,但我不想更改$PWD当前shell

值得注意的是,括号可以在函数定义中使用:

  • 正常用法:花括号:函数体在当前shell中执行;功能完成后,副作用仍然存在

    $ count_tmp() { cd /tmp; files=(*); echo "${#files[@]}"; }
    $ pwd; count_tmp; pwd
    /home/jackman
    11
    /tmp
    $ echo "${#files[@]}"
    11    
  • 异常用法:括号:函数体在子shell中执行;子外壳退出时,副作用消失

    $ cd ; unset files
    $ count_tmp() (cd /tmp; files=(*); echo "${#files[@]}")
    $ pwd; count_tmp; pwd
    /home/jackman
    11
    /home/jackman
    $ echo "${#files[@]}"
    0

文献资料


11
经过多年的shell开发,我不知道您可以使用括号在子shell中运行函数。避免污染全局名称空间的好主意!
l0b0

7
使用local关键字对清除这种污染大有帮助。
glenn jackman 2015年

2
是的,但是您必须记住要声明每个局部变量,这会使代码混乱。
l0b0 2015年

4
提示:如果要使用无副作用的函数,但要避免使用异常的函数声明语法(代码编辑人员可能不知道),则只需在函数调用上使用括号,而不要使用声明:pwd; (count_tmp); pwd;
Juve 2015年

2
到外壳... foo()(:;)等效于foo(){(:;); }如果您提出要求,它就是如何报告的!
安东尼

23

从官方bash文档中

()

( list )

将命令列表放在括号之间会导致创建一个子外壳环境,并且列表中的每个命令都将在该子外壳中执行。由于列表是在子shell中执行的,因此变量分配在子shell完成后不会保持有效。

{}

{ list; }

在大括号之间放置命令列表会导致该列表在当前Shell上下文中执行。没有创建子外壳。以下列表是分号(或换行符)。


9

“ {}”中的代码在当前线程/进程/环境中执行,并保留更改,更简洁地说,代码在当前作用域中运行。
'()'中的代码在单独的bash子进程内运行,执行后将其丢弃。这个子进程通常被称为子外壳,可以被认为是一个新的,类似于子的作用域。

作为示例,请考虑以下内容...

 ~ # { test_var=test }
 ~ # echo $test_var
 test
 ~ # ( test_var2=test2 )
 ~ # echo $test_var2

 ~ # 

请注意,在第一个示例中,带有'{}'的变量即使在结束'}'之后仍会设置,而在带有'()'的示例中,变量的设置不会超出'()'的范围。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.