
私は最近、次のアドバイスを含む答えを読みました。
しかし、一般的に言えば、⚠️あなたはしないでください
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では、関数が(再)定義されるとエイリアスが拡張され、エイリアスが複数の単語に拡張されると自動的に関数の追加コピーが取得されます。 (これは関数が単一の単語に展開された場合に取得できる名前です。)たとえば、上記の最初の例のエイリアスの場合とその両方が定義されますfoo
。bar
% alias foo='foo bar'
% foo() { echo hi; }
% typeset -p -f foo
foo () {
echo hi
}
% typeset -p -f bar
bar () {
echo hi
}
もちろん、同じ名前の関数とエイリアスがなければ、これらのいずれも発生しません。代わりに、必要なすべての機能を関数に含めることができます(特に、関数がある意味ではエイリアスよりも優れているため)。
これが深刻な問題を引き起こす可能性がある状況を想像することはできません。
私も。
initスクリプトの最初の部分がコマンドAを使用して潜在的に危険なアクションを実行した後(コマンド自体は必ずしも危険ではなく、特定の条件下で使用できます)、同じスクリプトの後続の部分がAをオーバーライドする場合は、次のことができますあります。初めて使用するときに関数やエイリアスが破損した場合、問題が発生します。
しかし、これは他の点でも脆弱です。たとえば、関数定義を一番上に移動するようにファイルを再構成すると、ファイルが破損し、同じ危険な動作が発生します。特に、関数/エイリアス定義の順序に従ってスクリプトを依存させないことをお勧めします。潜在的に危険なコマンドを実行するとき。
答え2
次の内容があるとしましょう.bashrc
。
foo=$(grep -m1 A /etc/os-release)
PS1="$foo %u $"
grep () { command grep -H "$@"; }
これはプロンプトに展開名を表示し、grep
常にファイル名のみを印刷する簡単な方法です。ファイルをリソースとして使用すると、プロンプトにファイル名も表示されます。何人かの人々はこれが驚くべきことではないと言うかもしれません。今、これらの行の間に何十もの異なるシェル構成があると想像してください。おそらく他のファイルにも存在する可能性があり、この設定は順番にデフォルトのrcファイルにあります。 (コマンドのエイリアスを生成するいくつかのソフトウェアの最近の例がありましたがenv
、これによりさまざまな用途が中断される可能性があります)。
bashrcを再取得することは、自分で書いたとしても難しいと言いたいです。 bashrcが十分に長い場合、それ自体は厳しい相互作用を引き起こす可能性があります。
答え3
シェル初期化がシステムに与える影響に慣れていない場合は、使用しないでください。本当にそうではありません。 UTBLTをしないでください! (ツールを学ぶ前にツールを使用してください)(ものを学ぶ前にものを使用してください)。
ほとんどのシェルは、-x
各コマンドの実行を表示するオプションを提供します。man
あなたのページを読んでください$SHELL
。
「よく書かれた」IMHOシェル初期化スクリプトは、環境変数、フラグファイルなどを調べて実行されたことを確認し、「正しい操作を実行」します。