web-dev-qa-db-ja.com

引用符付きと引用符なしの文字列展開

  1. for i in $(xrandr); do echo "$i" ; done
  2. for i in "$(xrandr)"; do echo "$i"; done
  3. for i in "$(xrandr)"; do echo $i; done

1が2と異なる理由を理解していますが、3が2とは異なる出力を提供するのはなぜですか?出力についても説明してください。引用符は改行でどのように機能しますか?

11
ManuelSchneid3r

引用符で囲まれていない変数(_$var_など)またはコマンド置換($(cmd)または_`cmd`_など)は、split + glob演算子ですボーンのようなシェルで。

つまり、それらの内容は、_$IFS_特殊変数の現在の値(デフォルトでは、スペース、タブ、改行文字を含む)に従って分割されます。

そして、その分割の結果として生じる各Wordは、ファイル名の生成globbingまたはとも呼ばれます)の対象になります。ファイル名の展開)、つまり、パターンと見なされ、そのパターンに一致するファイルのリストに展開されます。

したがって、for i in $(xrandr)では、$(xrandr)は引用符で囲まれていないため、スペース、タブ、および改行文字のシーケンスで分割されます。そして、その分割の結果として得られた各Wordは、一致するファイル名がチェックされ(または、どのファイルとも一致しない場合はそのまま残されます)、forはそれらすべてをループします。

for i in "$(xrandr)"では、コマンド置換が引用されているため、split + glob演算子を使用していないため、のループに1つのパスがあります。 one value:xrandrの出力(コマンド置換が削除される末尾の改行文字なし)。

ただし、_echo $i_では、_$i_が再び引用解除されるため、_$i_の内容が分割され、ファイル名生成の対象となり、それらが渡されますechoコマンドの個別の引数として(およびechoは、スペースで区切られた引数を出力します)。

学んだ教訓:

  • 単語分割またはファイル名生成が必要ない場合は、常に変数展開とコマンド置換を引用してください
  • 単語分割またはファイル名生成が必要な場合は、引用符で囲まずに、それに応じて_$IFS_を設定するか、またはを有効にします。必要に応じてファイル名の生成を無効にします(_set -f_、_set +f_)。

通常、上記の例では、xrandrの出力で空白で区切られた単語のリストをループする場合は、次のことを行う必要があります。

  • _$IFS_をデフォルト値のままにする(または設定を解除する)と、空白で分割されます
  • xrandrが_set -f_または_*_または_?_文字(ファイル名で使用されるワイルドカード)を出力しないことが確実でない限り、_[_を使用してファイル名生成を無効にします生成パターン)

そして、inループのfor部分でのみsplit + glob演算子を使用します(コマンド置換または変数展開は引用符で囲まないままにします)。

_set -f; unset -v IFS
for i in $(xrandr); do whatever with "$i"; done
_

xrandr出力の(空でない)をループする場合は、_$IFS_を改行文字に設定する必要があります:

_IFS='
'
_
19

引用された改行は改行です。そう echo "$1"はechoに単一のコマンドライン引数を与え、それは改行を直接出力します。

引用符で囲まれていない改行は空白です。そう echo $1はechoに多くのコマンドライン引数を与え、スペースで区切ってそれらを次々に出力します。

4
rici