将字符串转换为参数时击不解析报价(Bash doesn't parse quotes whe

2019-08-20 02:30发布

这是我的问题。 在bash 3:

$ test='One "This is two" Three'
$ set -- $test
$ echo $2
"This

如何获得的bash了解行情,并返回$ 2作为This is two ,而不是"This ?可惜我不能改变称为变量的建设test在这个例子中。

Answer 1:

发生这种情况的原因是因为在其中壳解析命令行的顺序的:它分析(并移除)报价和逃逸,然后替换变量值。 到时候$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

不幸的是,这需要的是如何创建的变量控制。



Answer 2:

现在我们有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]}"


Answer 3:

这个问题的解决方案是使用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


Answer 4:

我写了几本机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变量也可用于除空白指定字段分隔符。

如果您需要转义撇号可能会出现在不带引号的字段,这将需要一个小的变化-让我知道。



文章来源: Bash doesn't parse quotes when converting a string to arguments