在 bash 中何时使用 () 与 {}?

Fat*_*ind 85 bash scripts

我正在学习用 bash 编写 shell 脚本,我需要知道(...){...}. 编写脚本时如何在两者之间进行选择?

gle*_*man 101

如果您希望命令列表的副作用影响您当前的shell,请使用{...}
如果您想丢弃任何副作用,请使用(...)

例如,如果我:

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

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

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

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

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

文档

  • 经过多年的 shell 开发,我不知道您可以使用括号在子 shell 中运行函数。避免污染全局命名空间真是个好主意! (13认同)
  • 使用`local` 关键字对清除污染大有帮助。 (8认同)
  • *提示:*如果您想要无副作用的函数但要避免不寻常的函数声明语法(代码编辑器可能不知道),那么只需在函数调用上使用括号而不是声明:`pwd; (count_tmp); 密码;` (5认同)
  • 是的,但是您必须记住将每个变量声明为本地变量,这会使代码变得混乱。 (2认同)
  • 到外壳... foo() (:;) 等价于 foo() { (:;); 如果你问,它就是这样报告的! (2认同)

Dig*_*uma 29

来自官方bash 文档

()

( list )
Run Code Online (Sandbox Code Playgroud)

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

{}

{ list; }
Run Code Online (Sandbox Code Playgroud)

将命令列表放在大括号之间会导致列表在当前 shell 上下文中执行。没有创建子shell。以下列表中的分号(或换行符)是必需的。


smo*_*345 9

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

例如,考虑以下...

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

 ~ # 
Run Code Online (Sandbox Code Playgroud)

请注意,在带有 '{}' 的第一个示例中,即使在关闭了 '}' 之后,变量仍然设置,而在带有 '()' 的示例中,变量未设置在 '()' 的范围之外。

还要注意 '{}' 和 '()' 语法差异。这 ”;” '{}' 中的代码总是需要分隔符,但 '()' 中的代码不需要。


Ant*_*oni 5

(...)用于在子 shell 中运行代码。中间{...}使用的代码不会在子 shell 中使用。