在Bash中包含多个带引号的参数的变量

在Bash中包含多个带引号的参数的变量,bash,variables,escaping,quotes,Bash,Variables,Escaping,Quotes,我生成一个包含所有参数的bash变量,这些参数包含空格。 当我使用这些参数(例如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 ech

我生成一个包含所有参数的bash变量,这些参数包含空格。 当我使用这些参数(例如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"

这样,对于“文件、N1”、“文件和N2”

< P>,我有一些“没有这样的文件”错误,您可以考虑使用一个用于ARG的方法,例如:

args=( "$f1" "$f2" )
ls "${args[@]}"

(您现在遇到的问题是,一旦发生插值,文件名内和文件名间的空格就没有区别了。)

使用
set
将变量设置为位置参数;如果您通过
“$@”
“$1”
“$2”
等引用它们,则将保留引号。请确保在变量名称周围使用双引号

set -- "$f1" "$f2"
touch "$@"
ls "$@"
rm "$@"

这可能是最糟糕的答案,但你可以改变。这是“内部字段分隔符”,默认情况下等于空格+制表符+换行符

#!/bin/sh
IFS=,
MAR="-n,my file"
cat $MAR

上面的脚本将运行
cat
。第一个参数将是
-n
(编号行),第二个参数将是
my file

eval
将首先计算任何展开和引用,然后执行结果字符串,就像它已键入shell一样

f1="file n1"
f2="file n2"
args="'${f1//\'/}' '${f2//\'/}'"
# will execute `ls 'file n1' 'file n2'`
eval "ls $args"
上面的示例使用输入隔离来防止执行任意命令(
f1=“”;rm-rf“/”

使用<代码> EVA/COD>时,重要的是考虑数据源是“代码> EVA”D。如果

eval
用于命令合成(动态生成命令),且所有值都是静态的,并且由脚本定义,则可能没有其他考虑事项。如果您的脚本是一个持久化进程,以根用户身份运行,从世界可写管道读取值,那么最好确保用户输入始终被视为文字数据

上面的输入清理依赖于这样一个事实:单引号字符串被视为文本,即它们不被扩展,转义序列也不被处理。为了防止任意命令执行,我们需要防止单引号字符串被终止,这可以通过从输入中删除任何单引号来完成

如果确定不需要命令清除,则可以省略字符串替换:

f1="file n1"
f2="file n2"
args="'${f1}' '${f2}'"
# will execute `ls 'file n1' 'file n2'`
eval "ls $args"

编辑:这个答案被改写,以放置一个伤害可能性最小的例子。感谢@CharlesDuffy提醒您,示例在默认情况下应该是安全的。

这是否回答了您的问题@arran cudbard bell很好,没错,但问题多次提到了
bash
,因此此解决方案看起来是最佳答案。由于
eval
存在严重的安全问题,因此被否决-请参阅以获得更详细的解释,但基本上(从):“它会导致代码被解析两次而不是一次;这意味着,例如,如果代码中有变量引用,shell的解析器将计算该变量的内容。如果变量包含shell命令,则shell可能会运行该命令,无论您是否希望它运行该命令。“我同意@ArranCudbard Bell。您已经在使用变量参数执行可能的任意代码。使用
eval
不允许代码在这种情况下做任何超出其能力的事情。如果
f1=“”;rm-rf/;echo'
?eval很危险@siride,当代码只能由
ls
或甚至
rm
的参数组成时,这不是任意的——rm的参数不能,比如说,启动反向shell或下载rootkit。一个
eval
ed字符串可以做这些事情中的任何一件,也可以做其他任何事情;这是一个更大的风险。@siride,John的论点在
eval
和等价物中是正确的,而在其他方面则不然。参数扩展跳过了大多数解析阶段,而没有
eval
——它进行全局扩展和分词,但仅此而已<代码>不被识别,引号不被识别,其他参数扩展/命令替换/进程替换不被识别,等等。John评论最后一句中的摘要说eval是危险的,这是有原因的!,不使用您无法控制其值的变量是危险的!否,
eval
答案绝对是最差的。另请参见
#!/bin/sh
IFS=,
MAR="-n,my file"
cat $MAR