读取带空格的引用项目到数组中

时间:2012-10-16 23:19:54

标签: arrays bash

说我有文件foo.txt

"The" "quick brown" "fox" "jumps over" "the" "lazy dog."

我想将这些“字段”从文件读入数组。但是,如果字段有空格

,则我的尝试失败
$ read -a bar < foo.txt

$ echo ${bar[0]}
"The"

$ echo ${bar[1]}
"quick

我看到答案建议更改IFS,但这是一行,所以看起来没有帮助。

5 个答案:

答案 0 :(得分:2)

这是一个能完成这项工作的功能。对于大型字符串来说可能会很慢,但是可以正常工作,没有像任意代码执行或路径名扩展这样的警告:

#!/bin/bash

parse_quoted_items() {
    # Return array is parse_quoted_items_ary
    local line=$1
    parse_quoted_items_ary=() parse_quoted_items_error=
    while [[ $line ]]; do
        if [[ $line =~ ^[[:space:]]*\"([^\"]*)\"([[:space:]]+.+|)[[:space:]]*$ ]]; then
            parse_quoted_items_ary+=( "${BASH_REMATCH[1]}" )
            line=${BASH_REMATCH[2]}
        else
            parse_quoted_items_error=$line
            return 1
        fi
    done
}

然后你可以用作

IFS= read -r line < foo.txt
if parse_quoted_items "$line"; do
    declare -p parse_quoted_items_ary
else
    printf >&2 "There was an error parsing the string at %s\n" "$parse quoted_items_error"
    exit 1
fi

这不是一个令人满意的答案,但我怀疑有任何(安全)方法没有明确解析字符串。

答案 1 :(得分:1)

IFS无济于事。这有效:

eval bah=(`cat foo.txt`)

测试:

for i in "${bah[@]}"; do echo $i; done

答案 2 :(得分:1)

使用Perl:

IFS=$'\n' a=( $(perl -ne '@a = split (/("[^"]*")/); for (my $i=1; $i<@a; $i+=2) { print "$a[$i]\n" }' foo.txt) )

注意:这将比纯粹的bash解决方案慢,因为它必须启动Perl解释器。

<强>更新

对于Bash 4+:避免全局设置IFS

readarray -t a < <(perl -ne '@a = split (/("[^"]*")/); for (my $i=1; $i<@a; $i+=2) { print "$a[$i]\n" }' foo.txt)

答案 3 :(得分:1)

此解决方案类似于HåkonHægland的:

它还使用Bash的process substitutionreadarray/mapfile,但Perl部分有点短。

readarray -t words < <(cat fox.txt | perl -i -pe 's/(?<=") (?=")/\n/g')

或只是

readarray -t words < <( perl -pe 's/(?<=") (?=")/\n/g' fox.txt )

使用Perl替换处理该行,使用lookbehind和lookahead来检测"之后的空格,然后是另一个"。这些空格将替换为换行符,以允许readarray将每行读入数组words。然后将此多行输出传递到readarray-t将在将它们添加到数组之前去除尾随换行符。


请注意,在测试时我很难将perl的输出直接传递给readarray,它似乎永远不会读取数组中的一行,因为它是空的。正如@gniourf_gniourf指出的那样,事实上右手程序是在子shell中“绑定”在子shell中创建的任何变量的情况下启动的。

相关资源:

"I set variables in a loop that's in a pipeline. Why do they disappear after the loop terminates? Or, why can't I pipe data to read?"

有趣。

答案 4 :(得分:0)

$ . <(sed 's/^/set /' foo.txt)

$ echo $1
The

$ echo $2
quick brown