在源代码的 bash 脚本中使变量本地化的最佳方法?

Hay*_*iff 10 bash source shell-script

我有一个 bash 脚本,可以生成关于机器上一些长时间运行的作业的进度报告。基本上,这个父脚本循环遍历子脚本列表(用 调用它们source)。子脚本应该设置几个特定的​​变量,然后父脚本将使用这些变量。

今天发现一个bug,第一个子脚本设置的变量不小心被第二个子脚本使用,导致输出不正确。有没有一种干净的方法来防止这些类型的错误发生?

基本上,当我source是一个子脚本时,有几个特定的​​变量我想保留回父脚本。我的父脚本在source每个新的子脚本之前重置这些特定变量,因此它们没有问题。但是,某些子脚本可能具有它在本地使用的其他任意变量,这些变量不应保留回父脚本。

显然,我可以在子脚本的末尾手动取消设置其中的每一个,但是如果我忘记了它们,这些似乎很容易出错。是否有更合适的方法来获取脚本,并且只有某些变量保留在调用 的脚本中source

编辑:为了清楚起见,这是我的父脚本的一种简化版本:

echo "<html><body><h1>My jobs</h1>"

FILES=~/confs/*.sh
for f in $FILES; do
  # reset variables
  name="Unnamed job"
  secsSinceActive="Unknown"
  statusText="Unknown"

  # run the script that checks on the job
  source "$f"

  # print bit of report
  echo "<h3>$name</h3>"
  echo "<p>Last active: $secsSinceActive seconds ago</p>"
  echo "<p>Status: $statusText</p>"

echo "</body></html>"
Run Code Online (Sandbox Code Playgroud)

以下是其中一个子脚本的外观:

name="My awesome job"

nowTime=`expr $(date +%s) `
lastActiveTime=`expr $(date +%s -r ~/blah.log)`
secsSinceActive=`expr $nowTime - $lastActiveTime`

currentRaw=$(cat ~/blah.log | grep "Progress" | tail -n 1)
if [ -z "$currentRaw" ]; then
  statusText="Not running"
else
  statusText="In progress"
fi
Run Code Online (Sandbox Code Playgroud)

变量 $name、$secsSinceActive 和 $statusText 需要保留回父脚本,但是当子脚本终止时,所有其他变量都应该消失。

Mic*_*alH 14

将您想要获取的整个脚本包装到一个函数中,在您只想在函数中使用的声明之前添加 local,并在脚本末尾调用该函数。

func () {
    local name="My awesome job"

    nowTime=`expr $(date +%s) `
    lastActiveTime=`expr $(date +%s -r ~/blah.log)`
    local secsSinceActive=`expr $nowTime - $lastActiveTime`

    currentRaw=$(cat ~/blah.log | grep "Progress" | tail -n 1)
    if [ -z "$currentRaw" ]; then
      local statusText="Not running"
    else
      local statusText="In progress"
    fi
}
func
Run Code Online (Sandbox Code Playgroud)

  • 要清理函数本身,您可以在调用它之后使用 `unset -f func`。 (4认同)
  • imo 的最佳解决方案,但对于阅读此答案的人,请记住,上面的 `func()` 函数将继续存在于父作用域中,并对其造成污染;为了避免名称冲突,我所知道的最好的解决方案是给它一个丑陋的名字,比如`___this_main___()` (2认同)