Bash 嵌套引号和 eval

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9510362/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 01:41:53  来源:igfitidea点击:

Bash nested quotes and eval

bashnestedevalquotes

提问by Zeophlite

I'm having difficulty nested quotes within a bash script

我在 bash 脚本中难以嵌套引号

argv="su -c '$RVM_PATH wrapper $config_rvm \'$PASSENGER_RVM_BIN $command $options\'' web"
eval $argv

The above got me

以上让我

eval: line 162: unexpected EOF while looking for matching `''
eval: line 163: syntax error: unexpected end of file

回答by Zeophlite

argv="su -c \"$RVM_PATH wrapper $config_rvm \\"$PASSENGER_RVM_BIN $command $options\\"\" web"

回答by ruakh

That's because \'doesn't have any special meaning within a single-quoted string; it means simply "backslash, followed by end-of-string".

那是因为\'在单引号字符串中没有任何特殊含义;它的意思只是“反斜杠,后跟字符串结尾”。

One option is to use $'...'instead of '...'; that will let you use backslash-escapes. It would look like this:

一种选择是使用$'...'而不是'...'; 这将让您使用反斜杠转义。它看起来像这样:

argv="su -c $'$RVM_PATH wrapper $config_rvm \'$PASSENGER_RVM_BIN $command $options\'' web"

The downside is that if there's any chance that $RVM_PATH, $config_rvm, or any of the other variables could include a backslash, then it too could be interpreted as introducing a backslash-escape.

缺点是,如果有任何机会$RVM_PATH$config_rvm或任何其他变量可以包括一个反斜杠,那么它也可以解释为引入一个反斜杠转义。

回答by Ignacio Vazquez-Abrams

Use an array instead.

请改用数组。

#!/bin/bash
cmd=(echo "foo bar")
"${cmd[@]}"

回答by Tom Hale

Generic solution for evalwith correctly quoted arguments

eval正确引用参数的通用解决方案

The following function uses the shell's own quoting mechanism to that I don't have to worry about how to correctly quote things:

以下函数使用 shell 自己的引用机制,我不必担心如何正确引用事物:

function token_quote {
  local quoted=()
  for token; do
    quoted+=( "$(printf '%q' "$token")" )
  done
  printf '%s\n' "${quoted[*]}"
}

Example usage:

用法示例:

$ token_quote token 'single token' token
token single\ token token

Above, note the single token's space is quoted as \.

上面,请注意single token的空间被引用为\

$ set $(token_quote token 'single token' token)
$ eval printf '%s\n' "$@"
token
single token
token
$

This shows that the tokens are indeed kept separate.

这表明令牌确实是分开的。



Given some untrusted user input:

鉴于一些不受信任的用户输入:

% input="Trying to hack you; date"

Construct a command to eval:

构造一个命令来评估:

% cmd=(echo "User gave:" "$input")

Eval it, with seeminglycorrect quoting:

评估它,看似正确的引用:

% eval "$(echo "${cmd[@]}")"
User gave: Trying to hack you
Thu Sep 27 20:41:31 +07 2018

Note you were hacked. datewas executed rather than being printed literally.

注意你被黑了。date被执行而不是按字面打印。

Instead with token_quote():

取而代之的是token_quote()

% eval "$(token_quote "${cmd[@]}")"
User gave: Trying to hack you; date
%

evalisn't evil - it's just misunderstood :)

eval不是邪恶的-只是被误解了:)