ファイルから読み込み、forを使用してフィールドを分割しますが、引用符は保持します。

ファイルから読み込み、forを使用してフィールドを分割しますが、引用符は保持します。

これは私がbashシェルスクリプトから得ようとしているものです:

for a in "1" "2 3" "4 5 6"
do
  echo "a: $a"
done
a: 1
a: 2 3
a: 4 5 6

ただし、変数を使用すると、引用符が異なるように処理されます。

echo "\"1\" \"2 3\" \"4 5 6\"" > a.txt

cat a.txt
"1" "2 3" "4 5 6"

read aline < a.txt

変数を二重引用符で引用すると、次の結果が表示されます。

for b in "$aline"
do
  echo "b: $b"
done
b: "1" "2 3" "4 5 6"

引用符がない場合は、次のような結果が得られます。

for b in $aline
do
  echo "b: $b"
done
b: "1"
b: "2
b: 3"
b: "4
b: 5
b: 6"

最初の例のように変数の内容を処理する方法はありますか?

答え1

見積もりに加えて、パッケージ全体(変数/算術/コマンド拡張、ワイルドカードなど)の使用に同意する場合は、次のことができます。

echo '"a b" "x         y"' >a.txt

eval "set -- $(<a.txt)"
for b do
    printf 'b: %s\n' "$b"
done

b: a b
b: x         y

(または他の高度なシェル)ではなく、通常のシェルで機能するようにするには、に$(<a.txt)変更します。何が制御できるかわからない場合にのみ、このオプションを使用してください。そうでなければ、分割、コマンド拡張などを介してスクリプトを利用することは容易ではありません。$(cat a.txt)bashzshksha.txt;

ただし、これらのパラメータをコマンドに渡す場合は、xargs拡張なしで引用符のみを処理することを使用できます。

xargs <a.txt printf 'b: %s\n'

ただしxargs、これはシェル関数ではなく外部コマンドでのみ機能し、二重引用符内のバックスラッシュは一重引用符内のバックスラッシュのように無視され、複数行の文字列を解析できません。

後者の制限が問題にならない場合は、xargsラッパーまたは配列を介して引用パーサーとして使用できます。

mapfile -t args < <(xargs <a.txt printf '%s\n')
for b in "${args[@]}"; do
        printf 'b: %s\n' "$b"
done

答え2

bashそうでない場合ksh93ksh93シェルがbashとにかく模倣しようとする)、組み込みオプションを使用してcsvを読むことができます-Sreadcsvスタイルの引用を理解します)。

IFS=" " read -rSA array < a.txt
printf 'a: %s\n' "${array[@]}"

これにより、変数の内容をコードのように表示するパラメータ拡張フラグ(参照は理解されますが、コードは評価されません)とパラメータ拡張フラグをzsh使用してレベル1参照を削除できます。zzshzshevalQ

IFS= read -r line < a.txt
printf 'a: %s\n' "${(Q@)${(z)line}}"

@パラメータ拡張フラグは、動作を連想させる空の要素を保存するためのものですksh${array[@]}

a.txt複数行が含まれている場合は、zshコマンドをループに置き換えることができますread。引用符付き文字列が複数行にまたがる場合、各呼び出しは複数行を読み取ることができます。content=$(<a.txt)ksh93readwhileread

関連情報