このドキュメントの二重引用符配列拡張がここで機能しないのはなぜですか?

このドキュメントの二重引用符配列拡張がここで機能しないのはなぜですか?

2つの配列があります

$ arr1=( 1 2 2 3)
$ arr2=( 2 3 3 4)

二重引用符配列拡張のベストプラクティスに従うと、奇妙な出力が生成されるのはなぜですか?

$ tsort << EOF
> "${arr1[@]}" "${arr2[@]}"
> EOF
"1
"2
2
3
3"
4"

そして、ベストプラクティスに従わないと正しい結果が出ますか?私は何をすべきですか?ありがとうございます。

$ tsort << EOF
${arr1[@]} ${arr2[@]} 
EOF

1
2
3
4

ここでは、単語の分割がまだ行われていると思います。

$ wc -l << EOF
a    
b  
1
EOF
3

答え1

~からバッシュマニュアル:

[...]この文書のすべての行はパラメータ拡張、コマンド置換、および算術拡張を経て、文字の順序は無視され、 ''  \newline 、''、および''文字は\''を使用して引用する必要があります。\$`

引用符の削除、フィールドの分割、またはファイル名の拡張については何も言わないため、区切られた文書の引用符は文字通り受け入れられ、一般的な機能を実行しません。

答え2

もう一つの答え基本的に「なぜなら手動いえば「と言えますが、私の考えにはそんな人もいるようです。理由この行動の後ろに。

このタイプのリダイレクトは、行に次の項目のみが含まれるまで、現在のソースから入力を読み取るようにシェルに指示します。言葉(末尾の空白なし)が表示されます。そのポイントまで読み取ったすべての行は、次のように使用されます。標準入力[...]注文する。

[… ]

どんな部分でも言葉引用符が付いている場合、区切り文字は引用符を削除した結果です。言葉、ここのドキュメントの行は拡張されません。もし言葉引用符なしでここにある文書のすべての行に、パラメータ拡張、コマンド置換、および算術拡張[...]が適用されました。

(強調)。

コマンドラインで引用を検討する主な理由は次のとおりです。

  1. 行を分割してパラメータリストを生成する方法をシェルに伝えます(2つのパラメータに対して1つのa bパラメータ"a b")。
  2. ''拡張を実行する必要があるか(相対""または引用符なし)かどうかをシェルに伝えます。

標準入力を生成するときの最初の理由は適用されません。小川そして、パラメータの数に関する概念はありません。 2番目の理由は適用できますが、デザインの選択は引用の有無によってのみ拡張を制御します。言葉"EOF"vs。EOF)は無効にします。

私は何をすべきですか?

ここでストリームを作成することを覚えておく必要があります。引用符を使用する理由習慣その中に現れるのはもう有効ではありません。実際、前提はあなたが使用するすべての参考資料ですしなければならないストリームに表示されます。

予想以上に大きい場合、エスケープされていない引用符は消えます。違いなし。私はここにある文書が参照が保存されるべきであることをサポートして\"示していると思います。\'しかし、これは実際に使用すべき唯一の引用符です。現状は仕事をより簡単にします。

答え3

次に置き換えると、実際にtsort何が起こるかを見てみましょうcat

$ arr1=( 1 2 2 3 )
$ arr2=( 2 3 3 4 )
$ cat <<END
> "${arr1[@]}" "${arr2[@]}"
> END
"1 2 2 3" "2 3 3 4"

ご覧のように、ドキュメントは拡張配列値を含むテキスト文字列にすぎません。二重引用符はドキュメント自体の二重引用符から来ます(シェルはその${...}ビットにのみ興味を持ち、引用符の文字には触れません)。

二重引用符を削除するときの出力は同じですが、二重引用符はありません。

1 2 2 3 2 3 3 4

tsortこれは次のように解釈されます。

1 2   <-- first two numbers from arr1
2 3   <-- last two numbers from arr1
2 3   <-- first two numbers from arr2
3 4   <-- last two numbers from arr2

残念ながら、この特別な例を選択した理由は次のとおりです。

1 2   <-- first number from arr1 and arr2
2 3   <-- second number from arr1 and arr2
2 3   <-- etc.
3 4

つまり、各配列の項目は2つの列(各配列ごとに1つの列)に分割されます。

2番目のリストを(正しく)生成するには、実際にここでドキュメントを使用することはできません。代わりにシェルループを使用できます。

for (( i=0; i<${#arr1[@]}; ++i)); do
    printf '%d %d\n' "${arr1[i]}" "${arr2[i]}"
done | tsort

関連情報