エスケープ後にエイリアスをスキップするのはなぜですか?

エスケープ後にエイリアスをスキップするのはなぜですか?

エイリアスをスキップする一般的な方法は、aliasコマンドの前にバックスラッシュを追加することです。例えば、

$ alias ls='ls -l'
$ ls file
-rw-r--r-- 1 user user 70 Jul 30 14:37 file
$ \ls file
file

私の研究を通して、、、、などl\s"ls"別名をスキップする他の素晴らしい方法を学びました。l""sls''

しかし、この動作はどこに文書化されていますか?つまり、これはなぜ正しい動作ですか?これPOSIX仕様前にバックスラッシュがあるときにエイリアスを無効にする特別なケースについては、文書化された文書はないようです。私も見つけることができません。マイシェルマニュアル

これは自分で答える質問です。

答え1

キーは、シェル構文規則(セクション2.10)を適用する前に、シェルがエイリアス置換(セクション2.3.1)を実行することです。最初のステップはトークン認識(セクション2.3):

2.3トークン認識
トークンは、次のいずれかの規則に従ってトークンが分離されるまで、入力の現在の位置から開始する必要があります。トークンを構成する文字は、引用符で囲まれた文字を含む、入力の文字とまったく同じです。

(...トークン分離規則...)

トークンが区別されると、文法要件に従って分類されます。 シェル構文

2.3.1 エイリアスの置換
トークンが区切られた後、文法規則が適用される前に シェル構文、単純なコマンドとして認識されるコマンド名の単語の結果の単語が正しいことを確認する必要があります。引用しない、 有効なエイリアスです。

太字の部分を見ると、エイリアス照会フェーズに達するまで参照が削除されなかったという結論を下すことができます。 (バックスラッシュでエスケープするのも引用です。)

その後、\lsorを発行すると、シェルは正しいリテラル名であるか、またはでエイリアスをl\s探します。\lsl\sそのようなニックネームは可能ではありませんしたがって、エイリアス拡張は発生せず、シェルは文法規則に渡され、この時点で両方が私たちの長い友達として識別されますls。なぜなら」引用符のない<バックスラッシュ>は、後続の文字のリテラル値を保持する必要があります。」。 PATHシェル変数が一般変数の場合は、/bin/lsこのオプションを使用せずに実行します-l

"ls"これは、、、、、...エイリアスをスキップする理由も説明します'ls'l""sl''s

答え2

文書

バッシュマニュアルする録音してみてください。私のハイライト:

各単純なコマンドの最初の単語は引用なし、エイリアスがあることを確認してください。

mkshマニュアルから:

参照された単語が見つかると、エイリアス拡張プロセスが停止します(...)

zshマニュアルから:

エイリアス拡張は、履歴拡張を除く他の拡張の前にシェル入力に対して行われます。したがって、fooという単語にエイリアスが定義されている場合は、単語の一部を参照してエイリアスの拡張を避けることができます\foo。参照フォームのエイリアス定義を防ぐ方法はありませんが、すべての参照形式が可能です\foo

(何もありませんがsetopt posix_aliases。)

これはダッシュマニュアルとkshマニュアルよりも優れています。ダッシュマニュアルは予約語とエイリアスの前の参照を記述しますが、それらの間の相互作用は説明しません。 ksh マニュアルでは、予約語が引用されていない場合にのみ認識されると記載されていますが、エイリアスについてはこれを言及しません。

POSIXがこれをどのように指定するかを見ました。

基本的な

歴史的に、私はこれが部分的に言語設計の選択であり、部分的には実装を単純化するために登場したと思います。 Bourneシェルにはエイリアスはありませんが、引用符がない場合にのみ予約語を認識する動作があります。これは、パーサーが単語が予約されているかどうかを早期に知る必要があるため意味があります。特に、変数またはコマンド置換の結果を予約語として処理すると問題が発生します。考慮する:

if condition
then
command1
"$else_or_not_else"
command2
fi

conditionfalseで値がある場合はelse_or_not_else実行するelse必要がありますかcommand2?これを行うにはパーサーを拡張する必要があります$else_or_not_else。しかし、コードのこの部分はcondition偽なのでスキップしました! "else"をキーワードとして認識する必要がある場合、シェルパーサーは引用は処理しますが、置換は処理しないモードを持つ必要があるため、複雑さがさらにステップアップされます。

代替項目でエイリアスを識別する際にも問題があります。エイリアスは次のとおりです。

alias a='command1; $command2'

エイリアスには、;パーサーが考慮する必要があるコマンド区切り文字があります。変数置換後にエイリアス拡張が発生した場合は、変数置換後にパーサーを再度呼び出す必要があります。また、エイリアスを拡張するときに変数置換を再度呼び出す必要があります。そのため、代替項目でエイリアスを認識しないように、言語設計とインタプリタの実装を簡素化します。繰り返しますが、ユーザーが言語を理解し、実装者がソルバーを作成できるように、参照と置換を一緒に配置する方が簡単です。

予約語とエイリアスに対して同じ規則を維持することも単純化する要素です。

関連情報