for i in $(xrandr); do echo "$i" ; donefor i in "$(xrandr)"; do echo "$i"; donefor i in "$(xrandr)"; do echo $i; done
1が2と異なる理由を理解していますが、3が2とは異なる出力を提供するのはなぜですか?出力についても説明してください。引用符は改行でどのように機能しますか?
for i in $(xrandr); do echo "$i" ; donefor i in "$(xrandr)"; do echo "$i"; donefor i in "$(xrandr)"; do echo $i; done1が2と異なる理由を理解していますが、3が2とは異なる出力を提供するのはなぜですか?出力についても説明してください。引用符は改行でどのように機能しますか?
回答:
引用符で囲まれていない変数(など$var)またはコマンド置換($(cmd)またはなど`cmd`)は、Bourneのようなシェルのsplit + glob演算子です。
つまり、その内容は、$IFS特殊変数の現在の値(デフォルトではスペース、タブ、改行文字を含む)に従って分割されます。
そして、その分割の結果である各単語は、ファイル名生成(グロビングまたはファイル名展開とも呼ばれます)の対象になります。つまり、それらはパターンと見なされ、そのパターンに一致するファイルのリストに展開されます。
したがって、for i in $(xrandr)では$(xrandr)、は引用符で囲まれていないため、スペース、タブ、および改行文字のシーケンスで分割されます。そして、その分割の結果として得られる各単語は、一致するファイル名がチェックされ(または、どのファイルとも一致しない場合はそのまま残されます)、forそれらすべてに対してループします。
ではfor i in "$(xrandr)"、コマンド置換が引用符で囲まれているため、split + glob演算子を使用していません。ループの1つの値である1つの値の出力があります:(コマンド置換でxrandr削除される末尾の改行文字なし)。
ただし、echo $iでは$i再び引用符で囲まれていないため、の内容$iは分割され、ファイル名生成の対象となり、それらは個別の引数としてechoコマンドに渡されます(echoスペースで区切られた引数を出力します)。
学んだ教訓:
$IFSに応じて、および/または必要に応じて(有効または無効にファイル名の生成set -f、set +f)。通常、上記の例で、の出力で単語の空白で区切られたリストをループする場合はxrandr、次のようにする必要があります。
$IFS空白で分割するには、デフォルト値のままにする(または設定を解除する)set -fないことが確実でxrandrない限り、ファイル名生成を無効にするために使用します。*?[そしてin、forループの一部でsplit + glob演算子のみを使用します(コマンド置換または変数展開のみを引用符で囲まないでください)。
set -f; unset -v IFS
for i in $(xrandr); do whatever with "$i"; done
あなたは(空でない)をループにしたい場合はラインのxrandr出力は、セットに必要があると思い$IFS改行文字に:
IFS='
'
引用された改行は改行です。そのecho "$1"ため、echoに単一のコマンドライン引数を指定すると、改行が直接出力されます。
引用符で囲まれていない改行は空白です。そのecho $1ため、エコーするコマンドライン引数を多く与え、スペースで区切って次々に出力します。