eval 中的正确引用

eval 中的正确引用

我有一个脚本,除了执行位置参数之外什么也没做。 (我意识到安全风险,并且该脚本没有任何用处,因为它是一个最小的工作示例。)

$ cat script
> #!/usr/bin/env bash
>
> eval "${*}"


$ cat "docu ment"
> Lorem ipsum dolor sit amet

我想做的是用./script cat "docu ment", 或调用脚本./script cat docu\ ment,但是引号或转义字符消失,脚本将尝试cat docu ment,但这不起作用。在这种情况下我该如何修复引用?

编辑:我真正想做的是多次调用命令,直到它返回成功的退出代码,或者尝试了 n 次。我的脚本如下所示:

#!/usr/bin/env bash

# Try command several times, until it reports success (exit code 0)
# or I give up (tried n times)

tryMax=10
try=1

# Do until loop in bash
while
    eval "${@}"
    exitcode="${?}"
    [[ "${exitcode}" -ne 0 && "${try}" -lt "${tryMax}" ]]
do (( try++ ))
done

if [[ "${exitcode}" -ne 0 ]]; then
    echo -n "I tried hard, but did not manage to make this work. The exit code "
    echo "of the last iteration of this command was: ${exitcode}."
    exit "${exitcode}"
fi

答案1

你不需要eval这里。你可以只使用"$@"

while
    "${@}"
    exitcode="${?}"
    [[ "${exitcode}" -ne 0 && "${try}" -lt "${tryMax}" ]]
do ...

"$@"将扩展为脚本的所有参数作为单独的“单词”- 尊重阻止的原始引用分词- 进而让您使用第一个参数作为等待运行的命令( cat),其余参数作为cat( docu ment) 的参数。

这不起作用的地方:

  • "$@"如果您希望传入的命令使用其他更高级别的 shell 结构,例如管道、函数定义、循环等。这些都会在参数扩展之前处理,并且在扩展后不会再次尝试。
  • 如果命令的返回码被否定! cmd!也在处理命令开始时、参数扩展之前进行处理。
  • 如果命令是多个命令x \; yor 或$'x\ny',或者与orx $'\n' y相同。所有这些都只是常规争论。&&||
  • 如果您的命令前面有变量赋值,例如LD_LIBRARY_PATH=/x foo.您可以将它们放在脚本名称之前,但不能放在参数命令之前。
  • 如果命令中有重定向>foo,则3<bar在其中。这些可能会或可能不会附加到脚本,因为脚本有自己的日志输出。
  • 如果命令有此处文档或此处字符串。如果附加到脚本本身,这些内容只能读取一次,因此具体取决于命令失败的具体时间,您可能会或可能不会没事。无论如何,这些都很难适当地传递eval
  • 如果命令是子 shell( ... )或命令组{ ... ; }。这些将被视为称为 和 的命令,({不是语法结构。
  • 如果命令包含命令替换$(...) 需要重复运行。您可以使用它(或任何其他 shell 构造)来生成原始参数,但一旦脚本开始运行,它们都将是固定字符串。
  • 如果命令有任何其他应重复评估的元素,例如$RANDOM或一个算术展开$((i++))
  • 如果命令是time.这是 shell 保留字,并且不是内置命令,因此也在参数扩展之前进行处理。

然而,否则,您可以成功地eval完全避免,并且应该这样做。即使忽略任何可能的安全问题,正确构建它也非常脆弱。

相关内容