
Bash変数に複数行を保存しようとしても機能しないようです。
たとえば、/bin
1行にファイルを一覧表示して保存して$LS
から$LS
stdinに渡すと、wc
常に1が返されます。
$ ls -1 /bin | wc -l
134
$ LS=$(ls -1 /bin); wc -l <<< $LS
1
画面に出力しようとすると、さまざまな結果が表示されます。echo
すべての行を1行に印刷しますが、printf
最初の行だけを印刷します。
#!/bin/bash
LS=$(ls -1 /bin)
echo $LS
printf $LS
それでは、bash変数に複数の行を含めることができますか?
答え1
二重引用符で囲む必要があります(そしてしなければならない 二重引用符変数ほとんどの場合):
echo "$LS"
しかし、エコを使用しないでください変数の内容を印刷するには、次のようにします。printfに変更:
printf '%s\n' "$LS"
答え2
改行文字は変数にあります。LS=$(ls -1)
変数をLS
出力(出力が端末に行くことを除いてls -1
同じ出力を生成する)から末尾の改行を引いた出力に設定します。ls
問題は、改行文字を削除する値を印刷するときです。シェルスクリプトでは、$LS
「変数の値」を意味するのではなく、LS
「値を取得してLS
単語に分割し、IFS
各単語をグローブパターンとして解釈します」を意味します。値を取得するには、LS
を書くか、"$LS"
より一般的には$LS
二重引用符で囲む必要があります。
echo "$LS"
LS
バックスラッシュ文字を解釈するいくつかのシェルで始まるいくつかの値を除いて、印刷された値です-
。
printf "$LS"
LS
パーセントまたはバックスラッシュ文字を含まず(ほとんどの実装で)で始まらない限り、印刷する値-
。
値を正確に印刷するには、LS
を使用しますprintf %s "$LS"
。末尾に改行文字を追加するには、を使用しますprintf '%s\n' "$LS"
。
これは通常、$(ls)
現在のディレクトリにあるファイルのリストではありません。これは十分に飼いならされたファイル名がある場合にのみ機能します。ファイル名のリストを取得するには(ドットファイルを除く)、ワイルドカードを使用する必要があります*
。結果は文字列ではなく文字列のリストなので、文字列変数に割り当てることはできません。files=(*)
これをサポートするシェル(ksh93、bash、zsh)で配列変数を使用できます。
詳細については、次を参照してください。スペースやその他の特殊文字が原因でシェルスクリプトが停止するのはなぜですか?
答え3
前に述べた
printf '%s\n' "$LS"
唯一の正しい解決策です。
提案された他の解決策echo
そしてprintf
、まったく動作しません。
$ mkdir t
$ cd t
$ touch \\n
$ LS=$(ls -l)
$ echo "$LS"
total 0
-rw-r--r-- 1 domain domain 0 Nov 5 06:12
$ printf "$LS\n"
total 0
-rw-r--r-- 1 domain domain 0 Nov 5 06:12
$ printf '%s\n' "$LS"
total 0
-rw-r--r-- 1 domain domain 0 Nov 5 06:12 \n
$ ls -l
total 0
-rw-r--r-- 1 domain domain 0 Nov 5 06:12 \n
$ rm \\n
$ cd ..
$ rmdir t
$
V=$(printf 'line0:\\n\\n\nline1.\n') printf '%s\n' "$V"
(およびバリアントを使用してテストすることもできます。)
\n
ファイル名が一般的ではないかもしれませんが、git diff
変数に変換すると、リテラルに出会う可能性が\n
大幅に増えます。