我有一个 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
将整个脚本包装在函数中的一种变体是让source
d 脚本自行获取源代码通过一个函数:
让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
,输出:
这是如何工作的:
- 当
bleh
sources时blah.sh
,blah.sh
看到Ⓐ它已被获取并且Ⓑ它还没有通过 获取自身,这可以通过尚未设置的局部变量fun()
来证明。fun()
HACK_ACTIVATED
blah.sh
then 调用fun()
当前脚本并将其传递给该函数。fun()
将那些您希望保留为本地的变量设置为本地变量,然后递归地source
再次包含它的脚本 (blah.sh
)。
(我检查它是否来源的原因blah.sh
是因为,就我而言,该脚本也可以独立运行。)
答案3
我相信在 bash 中使变量成为本地变量的语法是:
local variable_name=
我知道这适用于函数,但不确定它如何与多个脚本一起使用。