2つの異なる結果を提供する2つの行を見てみましょう。
p=$(cd ~ && pwd) ; echo $p
p=$(cd ~ | pwd) ; echo $p
2つの違いは何ですか?
答え1
存在するp=$(cd ~ && pwd)
:
コマンドの置き換え、
$()
サブシェルで実行cd ~
~
ディレクトリを(ホームディレクトリ)に変更してcd
成功すると、保存&&
された文字列がホームディレクトリになるようにpwd
STDOUTにディレクトリ名を印刷します。p
/home/foobar
存在するp=$(cd ~ | pwd)
:
サブシェルの再
$()
生成両方のコマンドは
|
独自のサブシェルで実行されます(両方とも同時に開始されます)。これはサブシェルで
cd ~
行われますpwd
分離サブシェルpwd
したがって、コマンドを実行した場所のSTDOUTのみを取得できます。これは想像できるすべてのディレクトリである可能性があるため、p
ホームディレクトリではなくコマンドが呼び出されたディレクトリの名前が含まれます。
答え2
主な問題は、演算子を2つのコマンド &&
にリンクする方法です。|
終了コードでコマンドを接続します&&
。|
ファイル記述子(stdin、stdout)を介して2つのコマンドをリンクします。
まず、単純化してみましょう。割り当てを削除し、次のように作成できます。
echo $(cd ~ && pwd)
echo $(cd ~ | pwd)
分析のためにコマンド実行サブシェルを削除することもできます。
$ cd ~ && pwd
$ cd ~ | pwd
&&
たとえば、コマンドが実行されているディレクトリを表示するようにプロンプトを変更すると、PS1='\w\$ '
次のようになります。
/tmp/user$ cd ~ && pwd
/home/user
~$
- このコマンドは、
cd ~
「現在のディレクトリ」をコマンドを実行している実際のユーザーのホームディレクトリに変更します(/home/user
)。 - コマンドの結果は成功(終了コード0)なので、&&以降の次のコマンドが実行されます。
- 「現在の作業ディレクトリ」を印刷します。
- のプロンプトに示すように、実行中のシェルがに
pwd
変更されました。~
~$
何らかの理由で(ディレクトリが存在せず、権限がディレクトリの読み取りを妨げる)、ディレクトリの変更が失敗した場合(終了コードが0ではない)、次のコマンドは実行されません。
例:
/tmp/user$ false && pwd
/tmp/user$ _
終了コード 1 は、false
次のコマンドの実行を防ぎます。
したがって、「Command 1」の終了コードは「Command 2」に影響します。
これで、コマンド全体の効果は次のとおりです。
/tmp/user$ echo $(cd ~ && pwd)
/home/user
/tmp/user$ _
ディレクトリは変更されましたが、サブシェル内では$(…)
変更されたディレクトリが印刷されますが、/home/user
サブシェルが閉じるとすぐに削除されます。 pwdは初期ディレクトリ(/tmp/user
)に戻ります。
|
何が起こるのか?
/tmp/user$ cd ~ | pwd
/tmp/user
/tmp/user$ _
メタ文字|
(実際の演算子ではない)は、シェルにいわゆる「パイプ」を生成するように指示します。 (bashでは)|
パイプの両側の各コマンド()は右側のコマンドで始まり、各サブシェル内に設定されます。その後、左側に命令があります。/dev/stdin
右側のコマンドの入力ファイル記述子()が出力記述子(/dev/stdout
)に接続され、両方のコマンドが起動して対話します。左コマンド(cd -
)には出力がなく、右コマンド(pwd
)は入力を受け付けません。したがって、各シェルは独自のサブシェル内で独立して実行されます。
cd ~
シェルのパスワードを変更してください。pwd
別のサブシェルの(完全に別々の)パスワードを印刷します。
パイプラインが終了すると、各シェルの変更は削除され、外部サブシェルにpwdの変更はありません。
これが、これら2つのコマンドが「ファイル記述子」を介してのみ接続される理由です。
この場合、何も送信されず、何も読み取られません。
完全なコマンドは次のとおりです。
$ echo "$(cd ~ | pwd)"
コマンドが実行されたディレクトリのみが印刷されます。
答え3
2番目のケースでは、「|」を意味するかどうかはわかりません。
'|'シェルは、あるコマンドの出力を別のコマンドの入力にパイプします。一般的なユースケースは次のとおりです。
curl http://abcd.com/efgh | grep ijkl
1つのコマンドを実行し、別のコマンドを使用してコマンドの出力を処理します。
提示した例では、「cd」は通常出力を生成しませんが、「pwd」は入力を必要としないため、これは意味がありません。
'&&' と '||' はパートナーコマンドに過ぎません。論理AND演算子とOR演算子は、ほとんどの言語で使用されているのと同じ方法で設計されています。ただし、実行された最適化は特定の動作、つまりシェルプログラミングパラダイムを提供します。
論理AND演算の結果を確認するには、最初の条件が成功したら、2番目の条件を評価するだけです。最初の条件が失敗した場合、結果全体は常にfalseになります。
論理OR演算の結果を確認するには、最初の条件が失敗したときに2番目の条件を評価するだけです。最初の条件が成功すると、結果全体は常に真になります。
したがって、シェルは完了して成功した結果コードを返す場合command1 && command2
command2
にのみ実行されます。command1
存在する場合はcommand1 || command2
command2
完了時に実行されcommand1
、command1
そうであれば失敗コードを返します。
別の一般的な例はcommand1
テストコマンドです。これは単一行のif / thenステートメントを生成します。たとえば、次のようになります。
[ "$VAR" = "" ] && VAR="Value if empty"
これは、変数が現在空の場合に変数に値を割り当てる(冗長な)方法です。
Stack Exchangeの他の場所でもこのプロセスを使用する例がたくさんあります。