在 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"

这样,我对 "filen1""filen2 有一些“没有这样的文件”错误"

【问题讨论】:

***.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 或下载根工具包。 evaled 字符串可以做这些事情中的任何一个,或者其他任何事情;这是一个更大的风险。 @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 的变量的主要内容,如果未能解决你的问题,请参考以下文章

Linux 命令 | 文档编辑 | let : bash中的计算工具

Linux let 命令

在 C 字符串中包含双引号 (") [重复]

sql查询语句,where条件中包含单引号的解决方案

在返回语句中包含多个变量[重复]

php 笔记 2016/7/5