シェルの構成ファイルをインポートしないようにする理由はありますか?

シェルの構成ファイルをインポートしないようにする理由はありますか?

私は最近、次のアドバイスを含む答えを読みました。

しかし、一般的に言えば、⚠️あなたはしないでくださいsource ~/.zshrcドットファイルの内容によっては、さまざまな問題が発生する可能性があります。

私はOPにこれがなぜ問題になるのかについての例を尋ね、次のようなことを聞​​きました。

シェルの起動時にすでにインポートされているため、コマンドが実行される順序が重要な場合があります。簡単な例として、ファイルを入れてls() { command ls -x "$@" }; alias ls='ls -AF'シェル.zshrcを再起動するとsource ~/.zshrc...エラーが発生しますzsh: defining function based on alias ls'。これはかなり無害な例です。状況がより厳しくなる可能性があります

エラーを再現することはできませんが、これは妥当ですzsh。もっともらしいようですが、これが深刻な問題を引き起こす可能性がある状況は想像するのが難しいです。これらの問題は、クリーンな新しいセッションを開くときにも発生しません。。私が考えることができる最悪のシナリオはエラーメッセージを受け取ることですが、それを実装する方法さえわかりません。

rcもしそうなら、変更を現在のシェルセッションにインポートするためにシェルファイルを変更した後に手動でインポートすることを避けるべき妥当な理由はありますか?

私は長年この仕事をしてきたことを知っていますbash。定期的に機能を追加するか、機能を変更して~/.bashrcから. ~/.bashrc取得します。実際に深刻な問題を引き起こす可能性がある状況はありますか?私たちはいくつかの極端なケースを見つけることができると思いますが、これはそのような慈悲深い警告を正当化するのに十分ですか?たぶんzsh私がユーザーとして経験していないいくつかの特定の状況がありますかbash

Bourneファミリーシェル(bash、sh、zsh、kshなど)への回答に興味があります。

ベストアンサー1

同じ名前の関数とエイリアスを定義する初期化ファイルの例(init.shこれらの関数とエイリアス定義が使用されていると仮定)

foo() { echo "foo: $1"; }
alias foo='foo bar'
foo

バッシュ4.4と5.0:

初めて定義をロードすると正常に動作します。もしそうなら、.bashrcシェルの起動時にこれが起こります。

$ . init.sh
foo: bar

別の試みに失敗しました:

$ . init.sh
bash: init.sh: line 1: syntax error near unexpected token `('
bash: init.sh: line 1: `foo() { echo "foo: $1"; }'

関数名を引用またはエスケープすることも機能しません。

$ \foo() { echo "foo: $1"; }
bash: `\foo': not a valid identifier

unalias fooまず入る必要がありますinit.sh。または、コマンドラインの最初の単語ではないfunction foo { ... }ため、エイリアスを無視するを使用する必要があります。foo

Bashは実際にエイリアスを拡張するので、エイリアスがある単語を別の単語に変更すると、定義された関数の名前が変更されます。

$ alias foo=foobar; unset -f foo foobar
$ foo() { echo hi; }
$ typeset -p -f foo
bash: typeset: foo: not found
$ typeset -p -f foobar
foobar () 
{ 
    echo hi
}

エイリアスの内容に関係なく、現在のバージョンのZshではエラーが発生します。

% . ./init.sh
foo: bar
% . ./init.sh
./init.sh:1: defining function based on alias `foo'
./init.sh:1: parse error near `()'

ただし、zshでは関数名を引用またはエスケープすることができます。

それいつもそうではありませんたとえば、zsh 5.3.1では、関数が(再)定義されるとエイリアスが拡張され、エイリアスが複数の単語に拡張されると自動的に関数の追加コピーが取得されます。 (これは関数が単一の単語に展開された場合に取得できる名前です。)たとえば、上記の最初の例のエイリアスの場合とその両方が定義されますfoobar

% alias foo='foo bar'
% foo() { echo hi; }
% typeset -p -f foo
foo () {
        echo hi
}
% typeset -p -f bar
bar () {
        echo hi
}

もちろん、同じ名前の関数とエイリアスがなければ、これらのいずれも発生しません。代わりに、必要なすべての機能を関数に含めることができます(特に、関数がある意味ではエイリアスよりも優れているため)。


これが深刻な問題を引き起こす可能性がある状況を想像することはできません。

私も。

initスクリプトの最初の部分がコマンドAを使用して潜在的に危険なアクションを実行した後(コマンド自体は必ずしも危険ではなく、特定の条件下で使用できます)、同じスクリプトの後続の部分がAをオーバーライドする場合は、次のことができますあります。初めて使用するときに関数やエイリアスが破損した場合、問題が発生します。

しかし、これは他の点でも脆弱です。たとえば、関数定義を一番上に移動するようにファイルを再構成すると、ファイルが破損し、同じ危険な動作が発生します。特に、関数/エイリアス定義の順序に従ってスクリプトを依存させないことをお勧めします。潜在的に危険なコマンドを実行するとき。

おすすめ記事