ファイルをインポートする前にファイルが存在することをいつ(またはなぜ)確認する必要がありますか?

ファイルをインポートする前にファイルが存在することをいつ(またはなぜ)確認する必要がありますか?

ファイルをインポートしようとすると、ファイルが存在しないというエラーが表示され、何を修正するのかわかりませんか?

例えば、不揮発性これを設定ファイル/ rcに追加することをお勧めします。

export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm

上記のようにnvm.sh存在しない場合、「自動エラー」が発生します。しかし、試してみると. "$NVM_DIR/nvm.sh"結果が得られますFILE_PATH: No such file or directory

答え1

POSIXシェルには特別な.組み込みコマンドがあり、失敗するとシェルは終了します(たとえば、一部のシェルではbashPOSIXモードでのみ実行されます)。

エラーはシェルによって異なります。これらすべてがファイルを解析するときに構文エラーで終了するわけではありませんが、ほとんどはソースファイルが見つからないか開くことができないときに終了します。ソースファイルの最後のコマンドがゼロ以外の終了ステータスを返す場合(errexitもちろん、そのオプションがオンになっていない場合)、どのコマンドも終了することを知りません。

ここで:

[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"

この場合、ファイルが存在する場合はソースをインポートし、ファイルが-s存在しない場合(またはここで空の場合)はファイルソースをインポートしないようにします。

つまり、ファイルが存在しない場合はエラー(POSIXシェルの致命的なエラー)と見なされるべきではなく、ファイルはオプションと見なされます。

ファイルが読み取れない、またはディレクトリの場合、または(一部のシェルで)ファイルの解析中に構文エラーが発生した場合、これは依然として(致命的な)エラーであり、報告する必要がある実際のエラー条件になります。

一部の人々は競争条件があると主張しています。ところがそれを意味するのは、との間にファイルを削除するとシェルがエラーで終了するということですが、[スクリプト.の実行中にこの固定パスファイルが突然消えるため、これをエラーと考えるのが妥当だと思います。ランニング。

一方、

command . "$NVM_DIR/nvm.sh" 2> /dev/null

どこから¹がcommand削除されましたか?特別なコマンドの属性.(エラーが発生したときにシェルを終了しない)は影響を与えません。

  • エラーを非表示にし、.ソースファイルで実行されるコマンドのエラーも非表示にします。
  • また、無効な権限を持つファイルなどの実際のエラー条件を非表示にします。

他の一般的な構文(たとえば、オプションの環境ファイルを指定するDebianシステムの未変換initスクリプトを参照)は次のとおりですgrep -r /etc/default /etc/init*systemdEnvironmentFile=-/etc/default/service

  • [ -e "$file" ] && . "$file"

    ファイルが存在することを確認し、空の場合はインポートします。開くことができない場合でも、それは致命的なエラーです(それが存在していたか存在していても)。[ -f "$file" ](存在し、次のようなより多くのバリエーションを見ることができます。定期的なファイル)、[ -r "$file" ](読み取り可能)、またはそれらの組み合わせです。

  • [ ! -e "$file" ] || . "$file"

    少し良いバージョンです。ファイルが存在しないのが正常であることをより明確にします。これはまた、$?最後の命令実行の終了状態が反映されることを意味します$file(以前の場合を取得すると、それが存在しなかったためか、命令が失敗したためか1わかりません)。$file

  • command . "$file"

    ファイルが存在すると予想されるが説明できない場合は終了しないでください。

  • [ ! -e "$file" ] || command . "$file"

    上記の組み合わせ:ファイルが存在しないかどうかは重要ではありません。 POSIXシェルの場合、ファイルを開く(または解析)失敗が報告されますが、致命的ではありません(より適切である可能性があります~/.profile)。


1注:ただし、これはエミュレーションを除いて使用zshできませんcommandshKorn シェルでは、source実際には Korn シェルのエイリアスであり、command .特別ではないバリアントです。.

答え2

メンテナンス者のnvm回答:

nvmは単にファイルを削除することで簡単に削除できます。ソースnvmの行を追跡する追加の操作を強制することは特に価値がないようです。

私の説明(Stéphaneの素晴らしい説明とKusalalanandaの意見を組み合わせる):

よりシンプルで安全です。

さまざまな理由でファイルが見つからないため、起動時にPOSIXシェルが終了するのを防ぎます。 POSIX以外の(bashなど)シェルを使用しているユーザーは、必要に応じて条件を削除できます。

答え3

〜のようにしてくださいそしてスティーブン・チャジェラスPOSIXシェルから存在しないファイルを取得すると、ログインが失敗することが指摘されました。

ただし、ファイルが存在することを確認するためにテストを追加してからそのファイルをインポートしようとすると、競合状態という問題が発生する可能性があります。との間に何かを変更すると、回避しようとするnvm.shエラーが発生する可能性がありますが、これはまれです。[ -s nvm.sh ]. nvm.sh

一般に、競合状態を回避する方法は、目的の操作を試してから失敗した場合にエラーを処理することです。

. "$NVM_DIR/nvm.sh" || echo "Sourcing $NVM_DIR/nvm.sh failed" >&2

.上記のようにエラーが発生すると、エラー処理が実行される直前にシェルが終了するため、これはPOSIXシェルでは機能しないことがわかりました。

.bash_profile私の答えは、POSIXシェルをPOSIXモードで実行してはいけないので、この質問には関係ありません。したがって、とにかく上記のコードを実行できます。

セキュリティを最大化するためにPOSIXモードが機能しないようにするか、次に説明する技術を使用してPOSIXモードが無効になっていることを確認できます。https://unix.stackexchange.com/a/383581/3169

Stéphaneの答えには、すべてのPOSIXシェルを処理する方法に関するいくつかの便利な提案があります。これはnvmの作者の意図だと思いますが、ここで尋ねる質問とは少し異なるので、あなたに応じていくつかの可能なアプローチがあります。目標。

関連情報