web-dev-qa-db-ja.com

改行文字を削除するためのbashコマンドの置換を避ける方法は?

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

a=`df -H`

または

a=$( df -H )

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

echo $a

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

69
Laurent

末尾にない改行は削除されません

探している改行はそこにあります。変数をクォートせずに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
$ 

Trailing改行は削除されます

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

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


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

echoは削除された改行を追加するため(-nオプションで呼び出されない限り)、ほとんどの場合、これは重要ではありませんが、末尾に改行が複数あるEdgeの場合があります。プログラムの出力であり、何らかの理由で重要です。

回避策

1.ダミーキャラクターを追加する

これらの場合、@ Scrutinizerで述べたように、次の回避策を使用できます。

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


$ 

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

2.プロセス置換を使用した読み取り

コマンド置換を使用してプログラムの出力を変数に割り当てる代わりに、代わりに process substitution を使用して、 read組み込みコマンドへのプログラム(@ ormaajへのクレジット)。プロセス置換により、すべての改行が保持されます。出力を変数に読み込むのは少し難しいですが、次のようにすることができます。

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


$ 

説明:

  • 読み取りコマンドの internal field separatorIFS=でnullに設定します。そうでない場合、readは出力全体をvarに割り当てず、最初のトークンのみを割り当てます。
  • read をオプション-rd ''で呼び出します。 rは、バックスラッシュが特殊文字として機能するのを防ぐためのものであり、d ''で区切り文字を何も設定しないため、readは最初の行だけでなく出力全体を読み取ります。

3.パイプから読み取る

コマンドまたはプロセスの置換を使用してプログラムの出力を変数に割り当てる代わりに、プログラムの出力をreadコマンド(@ ormaaj)。配管もすべての改行を保持します。ただし、今回は the lastpipe builtin を使用して、shopt Shellオプション動作を設定します。これは、readコマンドが現在のシェル環境で実行されるために必要です。それ以外の場合、変数はサブシェルで割り当てられ、残りのスクリプトからはアクセスできません。

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


$
106
user000001

F#スクリプトでインタープリターを実行した結果をストリーミングするためにbashを使用していたため、これに頭を悩まそうとしていました。いくつかの試行錯誤の後、これは問題を解決することが判明しました。

$ cat fsi.ch
#!/bin/bash
echo "$(fsharpi --quiet --exec --nologo $1)"

$ fsi.ch messages.fsx
Welcome to my program. Choose from the menu:
new | show | remove

もちろん、ターミナルプログラムを実行する必要があると仮定します。お役に立てれば。

0
Alexander