bashエイリアスは、shopt expand_aliasesを使用しても展開されません


8

bash -c構成内でエイリアスを実行したい。

bashマニュアルには書かれています:

expand_aliasesシェルオプションが以下を使用して設定されていない限り、シェルがインタラクティブでない場合、エイリアスは展開されません。shopt

この例では、明示的hiに設定したときにエイリアスが見つからないのはなぜexpand_aliasesですか?

% bash -O expand_aliases -c "alias hi='echo hello'; alias; shopt expand_aliases; hi"
alias hi='echo hello'
expand_aliases  on
bash: hi: command not found

私は走っていGNU bash, version 5.0.0(1)-release (x86_64-pc-linux-gnu)ます。

コンテキスト:アイドル優先度でエイリアスを実行できるようにしたいと思います。

#!/bin/bash
exec chrt -i 0 nice -n 19 ionice -c 3 bash -c ". ~/.config/bash/aliases; shopt -s expand_aliases; $(shell-quote "$@")"

読まれbash -iたくないので使用は避けたい.bashrc


3
Bashマニュアルの引用文の直後の段落はこれをカバーしているようです: '...エイリアスは、コマンドが実行されたときではなく、読み込まれたときに展開されます。したがって、別のコマンドと同じ行にあるエイリアス定義は、次の入力行が読み取られるまで有効になりません。その行のエイリアス定義に続くコマンドは、新しいエイリアスの影響を受けません... '
Haxiel

ほとんどの場合と同様に、ここではエイリアスの代わりにシェル関数の使用を検討する必要があります。bash -c "hi () { echo hello; }; hi"出力hello
chepner

回答:


16

エイリアスを使用しているのと同じ行に設定すると、動作しないようです。おそらく、実際の解析段階の前に、コマンドライン処理の本当に早い段階でエイリアスがどのように展開されるかと関係があります。対話型シェル:

$ alias foo
bash: alias: foo: not found
$ alias foo='echo foo'; foo         # 2 
bash: foo: command not found
$ alias foo='echo bar'; foo         # 3
foo
$ foo
bar

使用されるエイリアスが1行遅れていることに注意してください。2番目のコマンドでは、設定されたエイリアスが見つかりません。3番目のコマンドでは、以前に設定されたエイリアスが使用されます。

したがって、-c文字列内に改行を入れれば機能します。

$ bash -c $'shopt -s expand_aliases; alias foo="echo foo";\n foo'
foo

(スクリプト内bash -O expand_aliases -c ...で使用する代わりに使用することもできshoptます。改行に役立つわけではありません。)

または、エイリアスの代わりにシェル関数を使用することもできます。他の方法でもはるかに優れています。

$ bash -c 'foo() { echo foo; }; foo'
foo

14

ilkkachuによって提案されたように、私のコメントを回答に変えます。

Bashマニュアル(質問でリンクされている)は、同じ行にエイリアス定義とコマンドがある場合のエイリアスの処理方法について説明しています。

引用(わかりやすくするために少しフォーマットされています):

エイリアスの定義と使用に関するルールはやや混乱します。bashは常に、少なくとも1つの入力行全体と、複合コマンドを構成するすべての行を読み取ってから、その行または複合コマンドでコマンドを実行します。

エイリアスは、コマンドが実行されるときではなく、読み取られるときに展開されます。したがって、別のコマンドと同じ行にあるエイリアス定義は、次の入力行が読み取られるまで有効になりません。その行のエイリアス定義に続くコマンドは、新しいエイリアスの影響を受けません。

この動作は、関数が実行されるときの問題でもあります。関数定義はそれ自体がコマンドであるため、関数の実行時ではなく、関数定義の読み取り時にエイリアスが展開されます。その結果、関数で定義されたエイリアスは、その関数が実行されるまで使用できません。

安全のために、エイリアスの定義は常に別の行に記述し、複合コマンドではエイリアスを使用しないでください。

ilkkachuの答えは、この問題に対する複数の可能な解決策を提供します。


FWIW、あなたの最後のコメントを見ましたが、答える時間がありませんでした。回答が他の人を補完するのは悪いことではありません。そのように実際に文書化されていることを知っている便利です。これを書いてくれてありがとう、今私は賛成票を投じることができます。:)
ilkkachu
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.