将字符串转换为参数时,Bash不解析引号

Dav*_*vid 11 string bash arguments spaces quoting

这是我的问题.在bash 3中:

$ test='One "This is two" Three'
$ set -- $test
$ echo $2
"This
Run Code Online (Sandbox Code Playgroud)

如何获得的bash了解行情,并返回$ 2作为This is two和不"This?不幸的是,我不能改变test这个例子中调用的变量的构造.

Gor*_*son 8

发生这种情况的原因是shell解析命令行的顺序:它解析(并删除)引号和转义,然后替换变量值.到$test被取代时One "This is two" Three,引号有其预期效果为时已晚.

这样做的简单(但危险)方法是添加另一级解析eval:

$ test='One "This is two" Three'
$ eval "set -- $test"
$ echo "$2"
This is two
Run Code Online (Sandbox Code Playgroud)

(请注意,echo命令中的引号不是必需的,但是通常的做法很好.)

我说这很危险的原因是它不仅仅会返回并重新引用引用的字符串,它会返回并重新解析所有内容,可能包括您不希望解释为命令替换的内容.假设你已经设定了

$ test='One `rm /some/important/file` Three'
Run Code Online (Sandbox Code Playgroud)

...... eval实际上会运行rm命令.因此,如果您不能指望$test"安全" 的内容,请不要使用此构造.

顺便说一下,做这种事情的正确方法是使用数组:

$ test=(One "This is two" Three)
$ set -- "${test[@]}"
$ echo "$2"
This is two
Run Code Online (Sandbox Code Playgroud)

不幸的是,这需要控制变量的创建方式.


Gri*_*ief 6

现在我们有了bash 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]}"
Run Code Online (Sandbox Code Playgroud)

输出,如预期:

One
This is two
Three
-n
foo     bar  # tabulation saved
Run Code Online (Sandbox Code Playgroud)

实际上,我不确定,但是可能在旧的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]}"
Run Code Online (Sandbox Code Playgroud)

  • 使用`echo`会在这里添加一些错误,`echo`加上一个不带引号的参数.如果`$ t = $'\ t'; qs_parse"One \"*\" - n \"标签$ {t}在$ {t}每个$ {t}字之间\""`,你不希望那些标签变成空格,或者`-n`作为`echo`的参数对待.考虑`printf'%s \n'"$ 1"`而不是. (2认同)