这是我的问题。 在bash 3:
$ test='One "This is two" Three'
$ set -- $test
$ echo $2
"This
如何获得的bash了解行情,并返回$ 2作为This is two
,而不是"This
?可惜我不能改变称为变量的建设test
在这个例子中。
这是我的问题。 在bash 3:
$ test='One "This is two" Three'
$ set -- $test
$ echo $2
"This
如何获得的bash了解行情,并返回$ 2作为This is two
,而不是"This
?可惜我不能改变称为变量的建设test
在这个例子中。
发生这种情况的原因是因为在其中壳解析命令行的顺序的:它分析(并移除)报价和逃逸,然后替换变量值。 到时候$test
被替换为One "This is two" Three
,为时已晚的报价有他们预期的效果。
简单(但危险)的方式来做到这一点是通过添加与解析的另一个层面eval
:
$ test='One "This is two" Three'
$ eval "set -- $test"
$ echo "$2"
This is two
(请注意,在引号echo
命令是没有必要的,但是是一个很好的一般做法。)
我说,这是危险的原因是,它不只是回去重新分析所引用的字符串,它可以追溯到和重新解析一切 ,也许包括你不想解释像命令替换的东西。 假设你已经建立
$ test='One `rm /some/important/file` Three'
... eval
将实际运行rm
命令。 所以,如果你不能在内容计数$test
是“安全的”, 不使用此结构 。
顺便说一句,做这样的事情的正确方法是用一个数组:
$ test=(One "This is two" Three)
$ set -- "${test[@]}"
$ echo "$2"
This is two
不幸的是,这需要的是如何创建的变量控制。
现在我们有4庆典,其中有可能做这样的事情:
#!/bin/bash
function qs_parse() {
readarray -t "$1" < <( printf "%s" "$2"|xargs -n 1 printf "%s\n" )
}
tab=' ' # tabulation here
qs_parse test "One 'This is two' Three -n 'foo${tab}bar'"
printf "%s\n" "${test[0]}"
printf "%s\n" "${test[1]}"
printf "%s\n" "${test[2]}"
printf "%s\n" "${test[3]}"
printf "%s\n" "${test[4]}"
输出,符合市场预期:
One
This is two
Three
-n
foo bar # tabulation saved
其实,我不知道,但它可能是可以做到的是,在这样的年龄较大的bash:
function qs_parse() {
local i=0
while IFS='' read -r line || [[ -n "$line" ]]; do
parsed_str[i]="${line}"
let i++
done < <( printf "%s\n" "$1"|xargs -n 1 printf "%s\n" )
}
tab=' ' # tabulation here
qs_parse "One 'This is two' Three -n 'foo${tab}bar'"
printf "%s\n" "${parsed_str[0]}"
printf "%s\n" "${parsed_str[1]}"
printf "%s\n" "${parsed_str[2]}"
printf "%s\n" "${parsed_str[3]}"
printf "%s\n" "${parsed_str[4]}"
这个问题的解决方案是使用xargs的(EVAL免费)。
它保留了双引号串在一起:
$ test='One "This is two" Three'
$ IFS=$'\n' arr=( $(xargs -n1 <<<"$test") )
$ printf '<%s>\n' "${arr[@]}"
<One>
<This is two>
<Three>
当然,你可以设置与阵列的位置参数:
$ set -- "${arr[@]}"
$ echo "$2"
This is two
我写了几本机bash的功能做到这一点: https://github.com/mblais/bash_ParseFields
您可以使用ParseFields
功能如下:
$ str='field1 field\ 2 "field 3"'
$ ParseFields -d "$str" a b c d
$ printf "|%s|\n|%s|\n|%s|\n|%s|\n" "$a" "$b" "$c" "$d"
|field1|
|field 2|
|field 3|
||
该-d
选项ParseFields删除任何引号和解释来自解析领域的反斜杠。
还有一个更简单的ParseField
功能(通过使用ParseFields
,在一个特定的字符串内的偏移解析的单个字段)。
请注意,这些功能无法解析流 ,只是一个字符串。 IFS变量也可用于除空白指定字段分隔符。
如果您需要转义撇号可能会出现在不带引号的字段,这将需要一个小的变化-让我知道。