这是一个问题:
在我的bash脚本中,我想通过一些检查来源几个文件,所以我有:
if [ -r foo ] ; then
source foo
else
logger -t $0 -p crit "unable to source foo"
exit 1
fi
if [ -r bar ] ; then
source bar
else
logger -t $0 -p crit "unable to source bar"
exit 1
fi
# ... etc ...
天真地我尝试创建一个函数:
function safe_source() {
if [ -r $1 ] ; then
source $1
else
logger -t $0 -p crit "unable to source $1"
exit 1
fi
}
safe_source foo
safe_source bar
# ... etc ...
但那里有一个障碍。
如果其中一个文件foo
,bar
等具有全局内容,例如 -
declare GLOBAL_VAR=42
- 它将有效地成为:
function safe_source() {
# ...
declare GLOBAL_VAR=42
# ...
}
因此全局变量变为本地变量。
问题:
bash中的别名似乎太弱了,所以我必须展开上面的功能,重复一遍,还是有更优雅的方法?
...是的,我同意Python,Perl,Ruby会让我的生活变得更轻松,但是在使用遗留系统时,人们并不总是有权选择最好的工具。
答案 0 :(得分:8)
是的,Bash的'eval'命令可以使这个工作。 'eval'不是很优雅,有时可能很难理解和调试使用它的代码。我通常会尽量避免它,但是Bash经常让你别无选择(比如提示你问题的情况)。你必须权衡使用'eval'的利弊。
如果您不熟悉'eval',那么它是一个Bash内置命令,希望您将字符串作为参数传递给它。 'eval'在当前的shell上下文和范围中动态地解释并执行您的字符串作为命令。以下是常用的基本示例(动态变量赋值):
$> a_var_name="color"
$> eval ${a_var_name}="blue"
$> echo -e "The color is ${color}."
The color is blue.
有关详细信息和示例,请参阅Advanced Bash脚本编写指南:http://tldp.org/LDP/abs/html/internal.html#EVALREF
要让'eval'处理您的采购问题,您首先要重写您的函数'safe_source()'。而不是实际执行命令,'safe_source()'应该只是在STDOUT上将命令作为字符串打印:
function safe_source() { echo eval " \
if [ -r $1 ] ; then \
source $1 ; \
else \
logger -t $0 -p crit \"unable to source $1\" ; \
exit 1 ; \
fi \
"; }
此外,您需要稍微更改函数调用,以实际执行'eval'命令:
`safe_source foo`
`safe_source bar`
(那些是反击/反引号,BTW。)
简而言之:
这有点复杂。就像我说的那样,'eval'并不是很优雅。特别是,您应该注意到有关我们所做的更改的一些特殊事项:
大多数这些变化都是由'eval'无法处理换行的事实所驱动的。如果我们将它们组合成由分号分隔的单行,它只能处理多个命令。新功能的换行符纯粹是人眼的格式化便利。
如果其中任何一个不清楚,请在Bash的'-x'(调试执行)标志打开的情况下运行您的脚本,这样可以让您更准确地了解正在发生的事情。例如,在函数上下文中,函数通过执行以下命令实际生成'eval'命令字符串:
echo eval ' if [ -r <INCL_FILE> ] ; then source <INCL_FILE> ; else logger -t <SCRIPT_NAME> -p crit "unable to source <INCL_FILE>" ; exit 1 ; fi '
然后,在主上下文中,主脚本执行:
eval if '[' -r <INCL_FILE> ']' ';' then source <INCL_FILE> ';' else logger -t <SCRIPT_NAME> -p crit '"unable' to source '<INCL_FILE>"' ';' exit 1 ';' fi
最后,再次在主上下文中,eval命令执行这两个命令(如果存在):
'[' -r <INCL_FILE> ']'
source <INCL_FILE>
祝你好运。
答案 1 :(得分:7)
这是一个迟到的答案,但现在declare
支持-g
参数,这使得变量全局变量(在函数内使用时)。源文件中的工作方式相同。
如果您需要全局(读取导出)变量,请使用:
declare -g DATA="Hello World, meow!"
答案 2 :(得分:1)
declare
使变量本地化为该函数。 export
会影响子进程的环境,而不会影响当前环境或父环境。
您可以在函数中设置变量的值,并在事后执行declare -r
,declare -i
或declare -ri
。