web-dev-qa-db-ja.com

bashビルトインの複数行出力をキャプチャする

通常、bashはコマンドの複数行の出力を割り当てることができます。

L=`ls`

これは、インタラクティブなシェルとスクリプトの両方から機能します。しかし、ビルトインの出力を変数に取り込むことができないようです。

L=`dirs -l -p`

これはインタラクティブシェルで機能しますが、スクリプトでは、おそらくbashによる組み込みの処理が異なるため、最初の行のみが変数になります。

なぜそれが起こるのですか、そしてどうすれば必要なことを行うことができますか?

6
Alex B

質問の言い方にはあいまいさがあります。あなたが言った:

しかし、スクリプトでは、最初の行だけが変数になります

そして、あなたのコメントは、スクリプトではなく、シェル関数を書いていることを示唆しています。

スクリプト内のcdは上位のシェルに伝播されないため、スクリプトはディレクトリの変更には役に立たないことをご存知だと思います。実際にスクリプトでディレクトリチェンジャーを開発しようとしている場合、ディレクトリスタックはnot従属シェルに継承されるため、苦労するでしょう。

_$ dirs -l
/home/msw /home/msw/Ubuntu One /home/msw /usr/bin /usr/local /bin /usr/local
$ cat > dirs.sh
dirs -l 
$ bash dirs.sh
/home/msw
_

あなたは助けるための関数を得ることができます:

_$ function passdirs() { bash ndirs.sh `dirs -l -p`; }
$ cat > ndirs.sh
echo $#
echo "$@"
$ passdirs
8
/home/msw /usr/local /usr/bin /bin /usr/local /usr/bin /bin /home/msw
_

ただし、もちろん、現在のシェルでcdにも影響を与える関数が必要です。この場合、コマンドラインでの引数のラップとアンラップは引用の雑用であるため、関数ですべてを実行するのが最善です。

_$ function cd_pattern() {
   cd $(dirs -l -p | grep --max-count=1 -e "$1") ; dirs
}
$ dirs
~ /usr/local /bin /usr/share/doc/evince ~/Ubuntu One
$ cd_pattern v..c
/usr/share/doc/evince /usr/local /bin /usr/share/doc/evince ~/Ubuntu One
_

また、引用の混乱を減らすために、バックティックの同義語として$(...)を使用するように切り替えました。

7
msw

コマンドの出力は、対話形式で実行するかスクリプト内で実行するかによって異なります。たとえば、「マルチライン出力」はexportでうまくいきます。

#! /bin/bash
L=`export`
echo "$L"

、インタラクティブに実行した場合とまったく同じようにすべての出力が得られます。

しかし、aliasではありません。

0
phunehehe