bash:function+;来源+;宣布=繁荣

bash:function+;来源+;宣布=繁荣,bash,function,Bash,Function,这里有一个问题: 在我的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 # ...

这里有一个问题:

在我的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
等具有全局--

--它将有效地成为:

function safe_source() {
  # ...
  declare GLOBAL_VAR=42
  # ...
}
因此,全局变量变为局部变量

问题:

bash中的别名似乎太弱了,所以我必须展开上面的函数并重复我自己的操作,还是有更优雅的方法


。。。是的,我同意Python、Perl、Ruby会让我的生活更轻松,但在使用遗留系统时,人们并不总是有权选择最好的工具。

函数内部的declare
会使变量成为该函数的局部变量<代码>导出影响子进程的环境,而不是当前或父环境


您可以在函数中设置变量的值,并在事后执行
declare-r
declare-i
declare-ri

是的,Bash的'eval'命令可以实现这一点“eval”不是很优雅,有时很难理解和调试使用它的代码。我通常会尽量避免,但Bash通常会让您别无选择(比如引发您的问题的情况)。你必须权衡自己使用“eval”的利弊

“评估”的一些背景 如果您不熟悉“eval”,它是一个Bash内置命令,希望您将字符串作为参数传递给它eval’在当前shell上下文和作用域中以命令的形式动态解释和执行字符串。下面是一个常见用法(动态变量赋值)的基本示例:

有关更多信息和示例,请参阅高级Bash脚本指南:

解决你的“源头”问题 要让“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`
(顺便说一句,这些是反勾号/反引号。)

工作原理 简言之:

  • 我们将函数转换为命令字符串发射器
  • 我们的新函数发出一个“eval”命令调用字符串
  • 我们的新backticks在子shell上下文中调用新函数,将函数输出的“eval”命令字符串返回到主脚本
  • 主脚本在主脚本上下文中执行backticks捕获的“eval”命令字符串
  • “eval”命令字符串在主脚本上下文中重新解析并执行“eval”命令字符串,运行整个if-then-else块,包括(如果文件存在)执行“source”命令
有点复杂。就像我说的,“eval”并不是很优雅。特别是,对于我们所做的更改,您应该注意以下几点:

  • 整个IF-THEN-ELSE块变成了一个完整的双引号字符串,每行末尾的反斜杠“隐藏”了换行符
  • 一些shell特殊字符(如“')已被反斜杠转义,而其他(“$”)未被转义
  • “echo 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 '
echo eval'如果[-r];则为震源;否则记录器-t-p crit“无法震源”;退出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 if'['-r']'';then source';else logger-t-p crit''canable'to source''”;'exit 1';'fi
最后,同样在主上下文中,eval命令执行这两个命令(如果存在):

'[' -r <INCL_FILE> ']'
source <INCL_FILE>
'['-r']'
来源

祝你好运。

回答有点晚,但现在
declare
支持一个
-g
参数,该参数使变量成为全局变量(当在函数中使用时)。同样适用于源文件

如果需要全局(读取导出)变量,请使用:

declare -g DATA="Hello World, meow!"

如果您使用
export
而不是
declare
,可能会起作用。我在简化。实际上我使用了
declare-r
(只读),有时使用
declare-ri
(只读,整数)当我放弃<代码>声明>代码>的时候,我也可以在需要时使用<代码> Read Ong/<代码>,但是我找不到一个替代的代码>声明-i <代码>。BTW,<代码>声明-X/COD>在一个函数中仍然是一个局部的。你真的需要使用<代码>声明-I/代码>,它的使用是不可变的吗?我可以考虑忽略它,因为我很确定,对于您试图用
声明
:)实现的目标,没有一个解决方案。我想您的意思是(Python、Perl、Ruby)将使您的生活不再简单,我想您的意思是将函数命名为safe而不是save source():)红牛的一个副作用,也许?
'[' -r <INCL_FILE> ']'
source <INCL_FILE>
declare -g DATA="Hello World, meow!"