在源 bash 脚本中使变量成为本地变量的最佳方法?

在源 bash 脚本中使变量成为本地变量的最佳方法?

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

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

基本上,当我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>"

其中一个子脚本可能如下所示:

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

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

答案1

将您想要获取的整个脚本包装到一个函数中,在您只想在函数中使用的声明之前添加 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

答案2

将整个脚本包装在函数中的一种变体是让sourced 脚本自行获取源代码通过一个函数:

bleh.sh成为source-ing 脚本

#!/bin/bash

echo -e "\x1b[34mI am  $(basename ${BASH_SOURCE[0]})\x1b[0m"

source blah.sh

echo -e "\x1b[34mStill $(basename ${BASH_SOURCE[0]})\x1b[0m"

echo -e "\x1b[34mA=$A\x1b[0m"
echo -e "\x1b[34mB=$B\x1b[0m"

和dblah.sh脚本source

#!/bin/bash

echo -e "\x1b[33mI am  $(basename ${BASH_SOURCE[0]})\x1b[0m"

fun() {
    local A
    local HACK_ACTIVATED=yes
    source "$1"
}

(return 0 2>/dev/null) && [ -z "$HACK_ACTIVATED" ] && {
    fun "${BASH_SOURCE[0]}"
    return
}

echo -e "\x1b[33mStill $(basename ${BASH_SOURCE[0]})\x1b[0m"

A=1
export B=1
echo -e "\x1b[33mA=$A\x1b[0m"
echo -e "\x1b[33mB=$B\x1b[0m"

运行时bleh.sh,输出:

在此输入图像描述

这是如何工作的:

  1. blehsources时blah.shblah.sh看到Ⓐ它已被获取并且Ⓑ它还没有通过 获取自身,这可以通过尚未设置的局部变量fun()来证明。fun()HACK_ACTIVATED
  2. blah.shthen 调用fun()当前脚本并将其传递给该函数。
  3. fun()将那些您希望保留为本地的变量设置为本地变量,然后递归地 source再次包含它的脚本 ( blah.sh)。

(我检查它是否来源的原因blah.sh是因为,就我而言,该脚本也可以独立运行。)

答案3

我相信在 bash 中使变量成为本地变量的语法是:

local variable_name=

我知道这适用于函数,但不确定它如何与多个脚本一起使用。

相关内容