shellcheck は basename を使用しないようにアドバイスしています。なぜでしょうか?

shellcheck は basename を使用しないようにアドバイスしています。なぜでしょうか?

試していますシェルチェック

私もそんなものを持っています

basename "${OPENSSL}" 

そして私は次の提案を受ける

Use parameter expansion instead, such as ${var##*/}.

実用的な観点からは違いは見当たりません

$ export OPENSSL=/opt/local/bin/openssl
$ basename ${OPENSSL}
openssl
$ echo ${OPENSSL##*/}
openssl

basenamePOSIX仕様なぜそれがベストプラクティスであるべきか理由がわかりません。何かヒントはありますか?

答え1

これは効率の問題ではなく、正確性の問題です。basenameは、出力するファイル名を区切るために改行を使用します。通常、ファイル名を 1 つだけ渡す場合は、出力の末尾に改行が追加されます。ファイル名自体に改行が含まれる場合があるため、これらのファイル名を正しく処理することが難しくなります。

さらに、人々は通常basename次のように使用します"$(basename "$file")"。これは、$(command)ストリップが全てから末尾の改行を削除します。改行で終わるcommandまれなケースを考えてみましょう。その場合、余分な改行が追加されますが、$filebasename"$(basename "$file")"両方改行が含まれるため、ファイル名が間違ってしまいます。

のもう 1 つの問題は、 (ダッシュまたはマイナス)で始まるbasename場合、オプションとして解釈されることです。これは簡単に修正できます。$file-$(basename -- "$file")

堅牢な使用方法はbasename次のとおりです。

# A file with three trailing newlines.
file=$'/tmp/evil\n\n\n'

# Add an 'x' so we can tell where $file's newlines end and basename's begin.
file_x="$(basename -- "$file"; printf x)"

# Strip off two trailing characters: the 'x' added by us and the newline added by basename. 
base="${file_x%??}"

代わりに を使用することもできますが、これは簡単ですが、独自のバグがあります。特に、またはの${file##*/}場合には誤りです。$file/foo/

答え2

shellcheckの関連行ソースコードは:

checkNeedlessCommands (T_SimpleCommand id _ (w:_)) | w `isCommand` "dirname" =
    style id "Use parameter expansion instead, such as ${var%/*}."
checkNeedlessCommands (T_SimpleCommand id _ (w:_)) | w `isCommand` "basename" =
    style id "Use parameter expansion instead, such as ${var##*/}."
checkNeedlessCommands _ = return ()

明確な説明はありませんが、関数名 ( checkNeedlessCommands) に基づくと、@jordanm の言う通り、新しいプロセスをフォークしないように提案しているようです。

答え3

dirnamebasenameなどreadlink(@Marco さん、ありがとうございます。修正されました)は、セキュリティが重要になったときに(パスのセキュリティが必要になったときに)、移植性の問題を引き起こす可能性があります。多くのシステム(Fedora Linux など)では に配置されます/binが、他のシステム(Mac OSX など)では に配置されます/usr/bin。また、Windows には Bash があり、cygwin、msys などがこれに該当します。 可能であれば、純粋な Bash のままにしておくことが常に望ましいです。(@Marco のコメントより)

ところで、shellcheck へのポインタをありがとうございます。これまで見たことがありませんでした。

関連情報