bash 中的局部变量:本地变量与子 shell

发布于 2024-10-11 11:06:44 字数 556 浏览 5 评论 0原文

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

例如:

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

或者

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

显然,使用子 shell 的版本编写起来更简单,因为您不必关心将所有变量声明为本地变量(更不用说由 getopts)。但我可以想象创建子 shell 会产生开销。

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

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.

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.

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

拔了角的鹿 2024-10-18 11:06:44

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

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

然而,就清晰度而言,最好是显式地声明变量 - 它降低了脚本中断的风险,因为有人出现并说“这个子 shell 显然不需要”(而且它确实不需要) t; 我想从你的函数中删除子外壳)。

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

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.

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.

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).

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'.

以酷 2024-10-18 11:06:44

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

我认为这非常容易出错,并且更喜欢始终使用子 shell 函数:

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

不需要声明局部变量 - 但也无法更改全局变量。我认为这很好!

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

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

f
echo "Did not exit"

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

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

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

这将退出

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:

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!

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文