我有一行我从文件中读取
line="1 \"Some Text Here\""
和一个带两个参数的函数
print() {
echo $1
echo $2
}
执行时
print $line
我得到的输出是
1
"Some
我想要的是
1
Some Text Here
答案 0 :(得分:5)
如果您信任输入,则可以使用eval
(通常要避免,因为恶意输入字符串可以执行不需要的操作):
line="1 \"Some Text Here\""
eval print "$line" # `print` is the shell function from the question
但是,即使使用无害的输入字符串,如果输入字符串包含所谓的 shell元字符:eval
,| & ; ( ) < >
命令也会中断。
此外,如果字符串碰巧包含看起来像路径名模式(globs)的*
等标记,它们会无意中被扩展;相关的模式字符为:* ? [ ]
。
因此,要使用\
输入字符串中的上述更强大的转义模式字符和元字符,如下所示:
eval print "$(sed 's/[][*?&;()<>]/\\&/g' <<<"$line")"
更新:事实证明不需要eval
:问题可以通过xargs
来解决,它识别字符串文字中引用的子串。:
#!/usr/bin/env bash
# Sample function that prints each argument passed to it separately
print() {
for arg; do
echo "[$arg]" # enclose value in [] to better see its boundaries
done
}
# Sample input string with embedded quoted strings, an unqoted
# glob-like string, and an string containing shell metacharacters
line="1 \"double-quoted string\" * 'single-quoted string' string-with-;|>-(metachars)"
# Let `xargs` split the string into lines (-n 1) and read the
# result into a bash array (read -ra).
# This relies on `xargs`' ability to recognize quoted strings embedded
# in a string literal.
IFS=$'\n' read -d '' -ra args <<<"$(xargs -n 1 printf '%s\n' <<<"$line")"
# Now pass the array to the `print` function.
print "${args[@]}"
结果:
[1]
[double-quoted string]
[*]
[single-quoted string]
[string-with-;|>-(metachars)]
注释和限制:
不带引号的令牌允许使用\
来转义嵌入字符,例如空格,单引号和双引号。
\
也被忽略,这可能是不受欢迎的;例如:echo 'a\b' | xargs # -> 'ab'
- 使用\\
,或者单引号或双引号。 引用令牌不需要内部\
- 转义,但遗憾的是,不支持嵌入相同类型的引号 - 似乎没有转义工作。
请注意,指定printf '%s\n'
作为xargs
执行的命令通常不是必需的,因为xargs
默认调用{{1}实用程序(不是shell builtin );但是,有些echo
实现会识别自己的选项,例如echo
(虽然不支持-e
),因此第一个输出令牌可能被误认为是选项。
相比之下,--
适用于所有情况。
带嵌入式换行符的引用字符串不受支持。 (printf '%s\n
在这种情况下报告解析错误) - 可能,这很少会出现问题。
答案 1 :(得分:0)
您需要使用变量IFS
。在您的脚本中键入IFS=\"
。这应该可以解决你的问题。
答案 2 :(得分:0)
根据您的具体情况,使用shift
可能对您有用。
例如:
print() {
echo "$1"
shift
echo "$*"
}
打印第一个参数,移动参数列表(删除第一个参数),然后打印其余参数。
那应该给你这个结果:
$ text="1 \"Multiple Words Here\""
$ print() {
> echo "$1"
> shift
> echo "$*"
> }
$ print $text
1
"Multiple Words Here"