{} と複数の `\ls` を使用した複雑なコマンド置換を理解する

{} と複数の `\ls` を使用した複雑なコマンド置換を理解する

シェル スクリプトのこの行を理解しようとしています。$(..)を実行して..、その出力を$()ステートメント内の該当する場所に挿入するという意味であることはわかっています。しかし、括弧の間では何が起こっているのでしょうか。 は何をしていて、前の行\lsの とどのように関係しているのでしょうか。 2 行に分割されていますか。通常の と同じですか。\\\\lsls

APPCLASSPATH=$CLASSPATH:$({ \
    \ls -1 "$VOLTDB_VOLTDB"/voltdb-*.jar; \
    \ls -1 "$VOLTDB_LIB"/*.jar; \
    \ls -1 "$VOLTDB_LIB"/extension/*.jar; \
} 2> /dev/null | paste -sd ':' - )

答え1

3 つのコマンドからの出力は、それらを値にマージするコマンドlsに渡されます。paste

$VOLTDB_VOLTDB"/voltdb-*.jar:$VOLTDB_LIB"/*.jar:$VOLTDB_LIB"/extension/*.jar

注記:変数$VOLTDB_VOLTDBとが展開され、これらのコマンド$VOLTDB_LIBごとに 1 つのファイルよりも多くの値が存在する可能性があります。そこにありますか? これはワイルドカードとして機能する glob 文字で、たとえば左側 (voltdb-) と右側 (.jar) の間の任意の値に展開されます。ls*

これらは一致します:

voltdb-1.jar
voltdb-blah.jar
voltdb-12345.jar

すべてが変数に含まれますAPPCLASSPATH

APPCLASSPATH=$CLASSPATH:$VOLTDB_VOLTDB"/voltdb....etc.

貼り付けコマンド

seq以下は、コマンドを使用して 1 ~ 10 の数字のシーケンスを生成する例です。

$ seq 10 | paste -sd ':' -
1:2:3:4:5:6:7:8:9:10

pasteコマンドが出力をマージし、コロン ( ) で区切っていることがわかります:

次のようにして例のコマンドを模倣することもできます。

$ { echo "hi1"; echo "hi2"; echo "hi3"; } | paste -sd ':' -
hi1:hi2:hi3

注記:paste コマンドのto-は、STDIN から入力を取得し、各引数を . で区切って入力順に印刷するように指示します:

さまざまなスイッチを使用すると、その後の「」pasteの数に基づいてデータをグループに分割することもできます。-

貼り付け例

ここに 2 の例を示します-

$ seq 10 | paste - -
1       2
3       4
5       6
7       8
9       10

ここに 3-があります。

$ seq 10 | paste - - -
1       2       3
4       5       6
7       8       9
10

つまり、各行にいくつpasteの引数を出力するかを指定していることになります。ただし、混乱しないでください。ここで扱っている例は、単に STDIN から入力を取得し、各引数をスペースで区切って、その後に を出力しているだけです。 を複数指定すると、一度に 2 つ、一度に 3 つなど、引数を取得するように指示していることになります。paste:-paste

引数は一度に 2 つ、:'s で区切られます。

$ seq 10 | paste -d ':' - -
1:2
3:4
5:6
7:8
9:10

$ seq 10 | paste -d ':' - - -
1:2:3
4:5:6
7:8:9
10::

ちなみに、スイッチを含めると、引数を連続して(シリアルに)受け取るように-s指示することになりpasteます。上記の例の 1 つでこれを使用した場合に何が起こるかを確認してください。

一度に2つ:

$ seq 10 | paste -sd ':' - -
1:2:3:4:5:6:7:8:9:10

一度に3つ:

$ seq 10 | paste -sd ':' - - -
1:2:3:4:5:6:7:8:9:10

答え2

$(command)コマンドを実行し、その出力を置き換えます。

{ list; }はグループ コマンドであり、現在のシェル環境で複数のコマンドを実行します。 に似ています(list)が、サブシェルを作成しません。

\commandコマンドのエイリアスを無視するために使用されます。エイリアスにより、コマンドの予想される動作が大幅に変更される可能性があります。

行末のは\、単にこの行が継続することを意味するため、シェルは次の行を現在の行の一部として認識します。通常、コンテキストからこれが明らかな場合 (開き括弧または引用符) は必要ありません。

答え3

APPCLASSPATH=$CLASSPATH:$({ \
    \ls -1 "$VOLTDB_VOLTDB"/voltdb-*.jar; \
    \ls -1 "$VOLTDB_LIB"/*.jar; \
    \ls -1 "$VOLTDB_LIB"/extension/*.jar; \
} 2> /dev/null | paste -sd ':' - )

\lsは と似ていますlsが、lsがエイリアスの場合、バックスラッシュによってエイリアスの展開が防止されます。これにより、コマンドが使用され、分類子サフィックス ( )lsなどの不要な出力を追加する可能性のあるエイリアスは使用されないことが保証されます。-F

ls既存のファイル名を引数として呼び出されるコマンドは、1 行に 1 つずつ引数をリストします。 の出力はターミナルではなくパイプに送られるため、 のオプションは効果が-1ありません。が既存のファイルの名前ではない引数を受け取った場合、標準出力には何も表示されず、代わりにエラーが表示されます。 コマンドからのエラーは によってどこにもリダイレクトされません。 がファイルではない引数を受け取る理由は 2 つあります。変数の 1 つが既存の読み取り可能なディレクトリを参照していない場合、またはワイルドカード パターンに一致するファイルがない場合です。どちらの場合も、パターンは展開されずに に渡されます。lslsls2> /dev/nulllsls

行末のバックスラッシュにより、シェルは後続の改行を無視します。バックスラッシュが使用されているすべてのポイントで、シェルはオプションの改行を期待しているため、ここではバックスラッシュはどれも役に立ちません。

中括弧 { … } はコマンドをグループ化します。複合コマンド{ \ls …; \ls …; \ls … ; }は にパイプされpaste、そのエラーは にリダイレクトされます/dev/null

このpasteコマンドは、間に を入れてすべての入力行を結合します。末尾にを付けないことを除いて、:と同じです。tr '\n' ::

コマンド置換により、$(…)の出力pasteが に補間されAPPCLASSPATH、変数 の値の後にCLASSPATHコロンが挿入されて 2 つの部分が区切られます。

簡略化されたバージョンを以下に示します。ワイルドカード パターンのいずれも一致しない場合は、末尾のコロンがなくてもAPPCLASSPATH等しくなります(おそらくこれが望ましいでしょう)。この点で、オリジナルとは少し異なります。CLASSPATH

APPCLASSPATH=$CLASSPATH:$(
  \ls "$VOLTDB_VOLTDB"/voltdb-*.jar "$VOLTDB_LIB"/*.jar "$VOLTDB_LIB"/extension/*.jar |
  tr '\n' :) 2>/dev/null
APPCLASSPATH=${APPCLASSPATH%:}

関連情報