bash 中的局部变量:local vs subshel​​l

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4625309/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-17 23:12:56  来源:igfitidea点击:

Local variables in bash: local vs subshell

bashfunctionvariableslocalsubshell

提问by Ignitor

As far as I know there are two ways to create local variables in a bash function: create a subshell or declare every variable as local.

据我所知,有两种方法可以在 bash 函数中创建局部变量:创建子 shell 或将每个变量声明为局部变量。

For example:

例如:

# using local
function foo
{
  local count
  for count in $(seq 10)
  do
    echo $count
  done
}

or

或者

# using subshell
function foo
{
  (
    for count in $(seq 10)
    do
      echo $count
    done
  )
}

Obvisously the version using the subshell is simpler to write because you don't have to care about declaring all variables local (not to mention (environment) variables created/exported by tools like getopts). But I could imagine that creating a subshell has an overhead.

显然,使用 subshel​​l 的版本编写起来更简单,因为您不必关心声明所有本地变量(更不用说由诸如getopts 之类的工具创建/导出的(环境)变量)。但是我可以想象创建一个子shell会有开销。

So what is the better approach? What are the pros/cons?

那么更好的方法是什么?有什么优点/缺点?

采纳答案by Jonathan Leffler

Creating a sub-shell involves a fork(), so it definitely has overhead compared with a local variable. While sub-shells are cheap — you don't worry about their cost when you need one — they are not free.

创建子外壳涉及 a fork(),因此与局部变量相比,它肯定有开销。虽然子炮弹很便宜——当你需要的时候你不用担心它们的成本——它们不是免费的。

If your script is going to be heavily used and performance really matters (so you'll have hundreds of users all running it at the same time, many times a day), then you might worry about the performance cost of the sub-shell. OTOH, if you run it once a month and the script as a whole runs for under 10 seconds, you probably wouldn't.

如果您的脚本将被大量使用并且性能确实很重要(因此您将有数百名用户同时运行它,一天多次),那么您可能会担心子 shell 的性能成本。OTOH,如果您每月运行一次并且整个脚本运行时间不到 10 秒,您可能不会。

However, in terms of clarity, it is much better to be explicit and declare the variables — it reduces the risk of the script breaking because someone comes along and says "this sub-shell clearly isn't needed" (and it really isn't; I'd want to remove the sub-shells from your functions).

但是,就清晰度而言,明确并声明变量要好得多 - 它降低了脚本破坏的风险,因为有人过来并说“显然不需要这个子shell”(实际上并不是) t; 我想从你的函数中删除子外壳)。

Look at the evolution of Perl scripts. They started off as a free-for-all with variables coming into existence on demand. They have gradually become more rigorous, with normal style now being to predeclare all variables. To some extent, shells have followed a similar path — but not as rigorously as Perl. Awk is also an interesting case study; its functions use global variables unless they are arguments to the function, which leads to functions being written with 3 active arguments (say) and 5 inactive arguments that effectively define local variables. It is slightly eccentric, though it 'works'.

看看 Perl 脚本的演变。他们一开始是免费的,变量按需产生。他们逐渐变得更加严谨,现在正常的风格是预先声明所有变量。在某种程度上,shell 遵循了类似的路径——但不像 Perl 那样严格。Awk 也是一个有趣的案例研究;它的函数使用全局变量,除非它们是函数的参数,这导致使用 3 个活动参数(例如)和 5 个有效定义局部变量的非活动参数编写函数。虽然它“有效”,但它有点古怪。

回答by Thomas

Now, making sure that all functions always declare all variables as local, is quite difficult.

现在,确保所有函数始终将所有变量声明为局部变量是非常困难的。

I think this is very error-prone and prefer to always use subshell-functions:

我认为这很容易出错,并且更喜欢始终使用 subshel​​l 函数:

f() (
 echo "we are a subshell"
)

No need to declare local variables - but also no way to change global variables. Which is GOOD in my opinion!

无需声明局部变量 - 但也无法更改全局变量。在我看来这很好!

One additional consequence is, that you always need to check the return / exit code of such functions and act accordingly! This is, because you cannot exit you script from within a subshell function!

另一个后果是,您始终需要检查此类函数的返回/退出代码并采取相应措施!这是因为您无法从子 shell 函数中退出脚本!

f() (
   echo "Trying to exit"
   exit 1
)

f
echo "Did not exit"

This will NOT exit your script. You need to do it this way:

这不会退出您的脚本。你需要这样做:

f() (
   echo "Trying to exit"
   exit 1
)

f || exit $?
echo "Did not exit"

This will exit

这将退出