Bashエイリアス-優先順位/シャドウイング(/非表示/失敗)

Aug 17 2020

.bashrcにいくつかのエイリアスを(この順序で)設定しています:

alias ls="lsc"
alias lsc='ls -Flatr --color=always'
alias lscR='ls -FlatrR --color=always'

alias調達後の確認:

alias ls='lsc'
alias lsc='ls -Flatr --color=always'
alias lscR='ls -FlatrR --color=always'

新しくエイリアスされたものを問題lsなく実行でき、lscエイリアスにチェーンされてから、lscエイリアスに関連付けられたコマンドを実行します。私も走ることができlscR、期待通りに動作します。

lscしかし、自分で実行しようとすると、次のようになります。

$ lsc
lsc: command not found

このシナリオでシェルがlscエイリアスをシャドウ/非表示にしているように見える理由はありますか?(ここで同じ結果を得るために「ls」を実行できるのに「lsc」を実行するのは無意味だと思いますが、このシナリオでのシェルの動作を理解しようとしています)。

編集:質問の回答で提供される(bash)シェルの動作に関する以下の回避策。

元の質問に対して、いくつかの非常に役立つ回答が提供されています。回答で説明されている拡張動作を短絡するために、2番目のエイリアスが既にエイリアス化されているコマンドを拡張しようとするのを防ぐ方法が少なくとも2つあるようです。たとえば、をalias cmd='cmd --stuff'呼び出すネイティブコマンドをオーバーライドしているcmd場合は、次の方法で、cmd他のエイリアス内のネイティブの代わりに「cmd」エイリアスが使用されないようにすることができます。

(この最初のアプローチに対するwjandreaのコメントに感謝します)

  1. cmd他のエイリアスで「コマンド」を前に付ける例:alias other-cmd-alias='command cmd --other-stuff'

または、

  1. 同様に、バックスラッシュ ''を前に付けることで、他のエイリアス内でエイリアスをエスケープできます(コマンドラインでも実行できます)alias other-cmd-alias='\cmd --other-stuff'

回答

13 John1024 Aug 17 2020 at 11:58

Bashでは、エイリアスにエイリアスを含めることができますが、無限ループに対する保護が組み込まれています。あなたの場合、入力するとlsc、bashは最初にエイリアスを次のように展開します。

ls -Flatr --color=always

lsはエイリアスでもあるため、bashはそれを次のように展開します。

lsc -Flatr --color=always

lscはエイリアスですが、かなり賢明なことに、bashはそれを2回拡張することを拒否します。、という名前のプログラムがあった場合lsc、bashはそれを実行します。しかし、ありません、そしてそれはあなたが得る理由ですcommand not found

補遺

lscR実行時は異なります。lscRに展開:

ls -FlatrR --color=always

lsはエイリアスなので、これは次のように展開されます。

lsc -FlatrR --color=always

lscはエイリアスなので、これは次のように展開されます。

ls -Flatr --color=always -FlatrR --color=always

lsすでに1回拡張されているため、bashは2回目の拡張を拒否します。と呼ばれる実際のコマンドがls存在するため、実行されます。

歴史

Schilyがコメントで指摘しているように、bashはkshからエイリアスを2回拡張しないという概念を借用しました。

さておき

エイリアスは便利ですが、それほど強力ではありません。引数の置換など、エイリアスを使用して複雑なことをしたい場合は、しないでください。代わりにシェル関数を使用してください。

6 muru Aug 17 2020 at 12:00

bashマニュアルから:

置換テキストの最初の単語はエイリアスについてテストされますが、展開されているエイリアスと同一の単語は2回目に展開されません。これは、たとえばlsls -F」にエイリアスを付けることができ、Bashが置換テキストを再帰的に展開しようとしないことを意味します。

ls、エイリアス、lsに展開されlsc、その後、再びls -Flatr --color=always、それ以来エイリアスの展開は、そこに停止しls、もともと拡張されていました。そのため、コマンドは正常に実行lsされ、外部コマンドに解決されます。

lsc、エイリアス、lscに展開されls -Flatr --color=always、その後、ls今まで展開されているlscし、そこので、エイリアスの展開は、停止しlsc、もともと拡張されていました。したがって、bashは他のを知らないため、コマンドは失敗しますlsc