1. ホーム
  2. bash

[解決済み] 改行文字を削除するbashコマンドの代入を避けるには?

2023-05-11 18:47:05

質問

bashスクリプトの実行を高速化するために、コマンドの結果をコマンド置換を使って変数に保持したいのですが、コマンド置換は 0x0A の改行文字をスペースに置き換えます。たとえば

a=`df -H`

または

a=$( df -H )

さらに処理を行いたい場合 $a を処理したい場合、改行文字はスペースに置き換えられ、すべての行が1行になり、grepするのが非常に難しくなります。

echo $a

コマンド置換で改行文字が削除されないようにするための簡単なトリックは何でしょうか?

どのように解決するのですか?

末尾にない改行が削除されない

探している改行はそこにあります。 echo を使っているからです。

バリデーション :

$ a=$( df -H )
$ echo $a
Filesystem Size Used Avail Use% Mounted on /dev/sda3 276G 50G 213G 19% / udev 2.1G 4.1k 2.1G 1% /dev tmpfs 832M 820k 832M 1% /run none 5.3M 0 5.3M 0% /run/lock none 2.1G 320k 2.1G 1% /run/shm
$ echo "$a"
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda3       276G   50G  213G  19% /
udev            2.1G  4.1k  2.1G   1% /dev
tmpfs           832M  820k  832M   1% /run
none            5.3M     0  5.3M   0% /run/lock
none            2.1G  320k  2.1G   1% /run/shm
$ 

末尾 は削除されます。

として ユーザー4815162342 が正しく指摘したように、出力内の改行は削除されませんが。 末尾の改行 はコマンド置換で除去されます。以下の実験を参照してください。

$ a=$'test\n\n'
$ echo "$a"
test


$ b=$(echo "$a")
$ echo "$b"
test
$

ほとんどの場合、これは重要ではありません。 echo は削除された改行を追加するからです (ただし、このコマンドが -n オプションで呼び出されない限り)、しかし、プログラムの出力に複数の末尾の改行があり、それが何らかの理由で重要であるようなエッジケースがいくつかあります。

回避策

1. ダミー文字を追加する

この場合 スクリプター が述べているように、以下のような回避策をとることができます。

$ a=$(printf 'test\n\n'; printf x); a=${a%x}
$ echo "$a"
test


$ 

説明 文字 x が出力に追加されます( printf x を使って)、改行の後に追加されます。改行が 末尾の でないため、コマンドの置換では削除されません。次のステップでは x を使って、追加した % 演算子で ${a%x} . これで、すべての改行が含まれた元の出力が得られました!

2. プロセス置換を使った読み込み

プログラムの出力を変数に代入するためにコマンド代入を使うのではなく、代わりに プロセス代入 に送り、プログラムの出力を read 組み込みコマンド(クレジット ormaaj ). プロセス置換ではすべての改行が保存されます。出力を変数に読み込むのはちょっと面倒ですが、次のようにすればよいでしょう。

$ IFS= read -rd '' var < <( printf 'test\n\n' ) 
$ echo "$var"
test


$ 

説明

  • を設定します。 内部フィールドの区切り文字 で、readコマンドをnullにすると IFS= . それ以外の場合は read に出力全体を割り当てることはできません。 var には割り当てられず、最初のトークンのみが割り当てられます。
  • を呼び出します。 read をオプションで起動します。 -rd '' . は r はバックスラッシュが特殊文字として機能しないようにするためのもので、バックスラッシュがある場合は d '' で区切り文字を無にすると、read が最初の行だけでなく、出力全体を読み込むようになります。

3. パイプからの読み込み

コマンドやプロセス代入を使ってプログラムの出力を変数に代入する代わりに、プログラムの出力をパイプで read コマンドを使うことができます (クレジット ormaaj ). パイピングはすべての改行も保存します。ただし、今回は lastpipe シェルのオプション動作として shopt ビルトイン . これは read コマンドが現在のシェル環境で実行されるようにするためです。そうでなければ、変数はサブシェルで割り当てられ、スクリプトの残りの部分からアクセスできなくなります。

$ cat test.sh 
#!/bin/bash
shopt -s lastpipe
printf "test\n\n" | IFS= read -rd '' var
echo "$var"
$ ./test.sh 
test


$