Bash:リモートで実行すると、改行の後のエイリアスが無視されるのはなぜですか?

Bash:リモートで実行すると、改行の後のエイリアスが無視されるのはなぜですか?

Bashでは、以下を実行します。

alias myalias='echo foo
echo bar
echo baz'
myalias

返品:

foo
bar
baz

しかし:

ssh localhost "shopt -s expand_aliases &>/dev/null;
alias myalias='echo foo
echo bar
echo baz'
myalias"

返品:

foo

なぜ?

答え1

私の考えでは、Bashでバグを見つけたようです。このエラーはオプションによって異なります-c

リモートでの実行は、複数行のエイリアスの問題とは関係ありません。ローカルbashで試してみてください。しかし、bashスクリプトやインタラクティブbashではなく、-c以下のオプションを試してみてください。

bash -c "shopt -s expand_aliases &>/dev/null;
alias myalias='echo foo
echo bar
echo baz'
myalias"

あなたの質問と同じ結果が表示されます。印刷のみ可能ですfoo

myalias正しい(予想)出力を得るためには、@cuonglmが提案したように、その後に少なくとも1行を追加する必要があります。

bash -c "shopt -s expand_aliases &>/dev/null;
alias myalias='echo foo
echo bar
echo baz'
myalias
:"

なぜですか? helpの後に追加の行があるのはなぜですかmyalias

私が言うのは、それが言葉にならないということです。 Bashには、この状況を説明または言及する文書はまったくありません。このように行動してはいけません。これは間違いです。コードを読んだ後は、この事実を確実に知ることができます。

問題のある最初のコマンドに戻ります。今回は何も変更する必要はありません。 bashを再コンパイルするだけです。「ONESHOT」が定義されていません。すると、正しい(予想された)出力が得られます。はい、よく聞きました。このコマンドはコンパイル時の設定が異なるため、2 つの異なる動作があります。

定義の有無にかかわらず、ONESHOTBashコードは2つの完全に異なるパスを生成します-c "command"。 ONESHOTが定義されていない場合、-c "command"対話型コマンドやbashスクリプトなど、ほとんどすべてのbash実行のためのコードパスである通常のコードパスが実行されます。ただし、ONESHOTが定義されている場合は、-c "command"フォークを回避してパフォーマンスを向上させるように設計された別の特定のパスが実行されます。

この場合、一般的で最も一般的な方法は正しい出力を提供できますが、特定の方法はそうではありません。私は一貫性のない行動がBashの作者が望むものではないと思います。どのような行動が正しいかについては、普段のやり方が正しいと考える傾向があります。

このエラーに関する詳細

次のコードはこのエラーに関連しています。これは buildins/evalstring.c ファイルの parse_and_execute() 関数から来ます。

while (*(bash_input.location.string))
  {
    ...
  }

ループwhileは行単位で実行され、ループ内の1行を処理します。コマンドの最後の読み取り行以降myalias(上記参照)条件はwhilefalseになります。myalias3行のエコーに拡張されましたが、今回は1つのエコーのみが処理されます。残りの2つのエコーは次のループで処理されますが...他のループはありません。

myalias読んだ後に別の行を追加すると、myaliasinの条件はwhiletrueに保たれるため、他の2つのエコーは次のループで実行される機会があります。その後の最後の行は、myaliasすべての拡張エコーが処理された後に処理されます。myalias

修正する

この質問に関連するBashのバージョンは次のとおりです。

GNU bash, version 4.4.12(1)-release (x86_64-pc-linux-gnu)

答え2

回避策(@cuonglmからインスピレーションを得てください):

ssh localhost "shopt -s expand_aliases &>/dev/null;
alias myalias='ls
echo foo
echo bar
echo baz'
myalias &&
true"

これにより終了コードが保存されます。しかしtrue〜しなければならない新しい道を選んでください。

まだその理由を説明していません。しかし、それはますます間違いのように見えます。

関連情報