在 Bash 中包含多个带引号的 args 的变量
Posted
技术标签:
【中文标题】在 Bash 中包含多个带引号的 args 的变量【英文标题】:Variable containing multiple args with quotes in Bash 【发布时间】:2011-11-19 06:01:30 【问题描述】:我生成了一个 bash 变量,其中包含我所有的 args,而这些 args 包含空格。 当我使用这些参数启动命令时 - 例如。 ls $args - 引号没有被正确解释。 这是一个示例 - 还创建和删除所需的文件。
#!/bin/bash
f1="file n1"
f2="file n2"
# create files
touch "$f1" "$f2"
# concatenate arguments
args="\"$f1\" \"$f2\""
# Print arguments, then launch 'ls' command
echo "arguments :" $args
ls $args
# delete files
rm "$f1" "$f2"
这样,我对 "file、n1"、"file 和 n2 有一些“没有这样的文件”错误"
【问题讨论】:
***.com/questions/2005192/… 这能回答你的问题吗? How to store a command in a variable in a shell script? 【参考方案1】:您可以考虑使用 array 作为参数,如下所示:
args=( "$f1" "$f2" )
ls "$args[@]"
(您现在遇到的问题是,一旦发生插值,文件内和文件间名称空间之间就没有区别了。)
【讨论】:
@arran-cudbard-bell 嗯,没错,但问题多次提到bash
,所以这个解决方案看起来是最佳答案。【参考方案2】:
eval
将首先评估任何扩展和引用,然后执行生成的字符串,就像它已被键入到 shell 中一样。
f1="file n1"
f2="file n2"
args="'$f1//\'/' '$f2//\'/'"
# will execute `ls 'file n1' 'file n2'`
eval "ls $args"
以上示例使用输入清理来防止执行任意命令 (f1="'; rm -rf '/"
)。
当使用eval
时,重要的是要考虑数据的来源是eval
'd。如果eval
用于命令合成(动态构建命令),所有值都是静态的,并且由您的脚本定义,则可能没有其他注意事项。如果您的脚本是一个持久进程,以 root 身份运行,从世界可写管道读取值,那么确保用户输入始终被视为文字数据可能是个好主意。
上面的输入清理依赖于单引号字符串被视为文字的事实,也就是说,它们不被扩展,并且不处理转义序列。为了防止任意命令执行,我们需要防止单引号字符串被终止,这可以通过从输入中删除任何单引号来完成。
如果您确定不需要命令清理,则可以省略字符串替换:
f1="file n1"
f2="file n2"
args="'$f1' '$f2'"
# will execute `ls 'file n1' 'file n2'`
eval "ls $args"
编辑:这个答案被重写以首先放置一个危害最小的例子。感谢@CharlesDuffy 提醒示例默认情况下应该是安全的。
【讨论】:
投反对票,因为eval
存在严重的安全问题 - 请参阅***.com/a/37573041/120818 以获得更详细的解释,但基本上(来自mywiki.wooledge.org/BashFAQ/048):“它会导致您的代码被解析两次而不是一次;这意味着,例如,如果您的代码中包含变量引用,shell 的解析器将评估该变量的内容。如果变量包含 shell 命令,shell 可能会运行该命令,无论您是否愿意。 "
我同意@ArranCudbard-Bell。您已经在使用可变参数执行潜在的任意代码。使用eval
不允许代码做任何超出它在这种情况下已经可以做的事情。
如果f1="'; rm -rf /; echo '"
怎么办? eval 很危险!
@siride,当代码只能包含 ls
甚至 rm
的参数时,这不是任意的——例如,rm 的参数不能启动反向 shell 或下载根工具包。 eval
ed 字符串可以做这些事情中的任何一个,或者其他任何事情;这是一个更大的风险。
@siride,John 的论点对于 eval
和等价物是正确的,否则不是。参数扩展在没有eval
的情况下跳过了大部分解析阶段——它会进行全局扩展和分词,仅此而已。 ;
无法识别,引号无法识别,附加参数扩展/命令替换/进程替换无法识别,等等。John 的评论最后一句中的摘要说 reason eval 是危险的!,而不是 使用您无法控制的值的变量是危险的!【参考方案3】:
使用set
将变量设置为位置参数;如果您通过"$@"
或"$1"
、"$2"
等方式引用它们,则引用将被保留。请确保在变量名周围使用双引号。
set -- "$f1" "$f2"
touch "$@"
ls "$@"
rm "$@"
【讨论】:
另见When to wrap quotes around a shell variable?【参考方案4】:这可能是最糟糕的答案,但您可以更改IFS。这是“内部字段分隔符”,默认等于空格+制表符+换行符。
#!/bin/sh
IFS=,
MAR="-n,my file"
cat $MAR
上面的脚本将运行cat
。第一个参数是-n
(编号的行),第二个参数是my file
。
【讨论】:
不,eval
的答案绝对是最糟糕的。以上是关于在 Bash 中包含多个带引号的 args 的变量的主要内容,如果未能解决你的问题,请参考以下文章