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

问题描述 投票:0回答:4

我生成了一个包含所有参数的 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"

有了这个,我有一些“没有这样的文件”错误 "file, n1", "file and n2"

bash variables escaping quotes
4个回答
80
投票

您可能会考虑使用 array 作为参数,像这样:

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

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


37
投票

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 提醒示例默认情况下应该是安全的。


9
投票

使用

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

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

5
投票

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

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

上面的脚本将运行

cat
。第一个参数将是
-n
(编号行),第二个参数将是
my file
.

© www.soinside.com 2019 - 2024. All rights reserved.