3

私がファイルを持っていると言う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がありますが、これは1行なので、役に立たないように見えます。

4

5 に答える 5

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

これは満足のいく答えではありませんが、文字列を明示的に解析しない(安全な)方法があるとは思えません。

于 2014-12-27T11:43:21.290 に答える
1

IFS助けにはなりません。これは機能します:

eval bah=(`cat foo.txt`)

テスト:

for i in "${bah[@]}"; do echo $i; done
于 2014-12-27T08:25:26.410 に答える
1

Perlの使用:

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

注:これは、Perlインタープリターを起動する必要があるため、純粋なbashソリューションよりも遅くなります。

アップデート:

Bash 4以降の場合:IFSグローバルに設定しないようにするには:

readarray -t a < <(perl -ne '@a = split (/("[^"]*")/); for (my $i=1; $i<@a; $i+=2) { print "$a[$i]\n" }' foo.txt)
于 2014-12-27T10:31:57.540 に答える
1

このソリューションは、HåkonHæglandのソリューションに似ています。

また、Bashのプロセス置換およびreadarray/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置換を使用して処理され、aの"後に続くスペースと別のスペースが続くスペースを検出します"。これらのスペースは改行に置き換えられ、readarray各行を配列に読み込むことができwordsます。次に、この複数行の出力がに渡されreadarray-t配列に追加する前に末尾の改行が削除されます。


perlこれをテストしている間、出力を直接に単純にパイプするのに問題があったことに注意してreadarrayください。配列が空であるため、配列に行を読み取らないように見えました。@gniourf_gniourfが指摘したように、これは、右側のプログラムがサブシェルで開始され、そのサブシェル内で作成された変数を「バインド」するという事実と関係があります。

関連リソース:

「パイプラインにあるループに変数を設定しました。ループが終了すると変数が消えるのはなぜですか?または、データをパイプして読み取れないのはなぜですか?」

面白い。

于 2014-12-27T13:21:24.570 に答える
0
$ . <(sed 's/^/set /' foo.txt)

$ echo $1
The

$ echo $2
quick brown
于 2014-12-27T06:41:42.410 に答える