答え1
これは効率の問題ではなく、正確性の問題です。basename
は、出力するファイル名を区切るために改行を使用します。通常、ファイル名を 1 つだけ渡す場合は、出力の末尾に改行が追加されます。ファイル名自体に改行が含まれる場合があるため、これらのファイル名を正しく処理することが難しくなります。
さらに、人々は通常basename
次のように使用します"$(basename "$file")"
。これは、$(command)
ストリップが全てから末尾の改行を削除します。改行で終わるcommand
まれなケースを考えてみましょう。その場合、余分な改行が追加されますが、$file
basename
"$(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
dirname
、basename
などreadlink
(@Marco さん、ありがとうございます。修正されました)は、セキュリティが重要になったときに(パスのセキュリティが必要になったときに)、移植性の問題を引き起こす可能性があります。多くのシステム(Fedora Linux など)では に配置されます/bin
が、他のシステム(Mac OSX など)では に配置されます/usr/bin
。また、Windows には Bash があり、cygwin、msys などがこれに該当します。 可能であれば、純粋な Bash のままにしておくことが常に望ましいです。(@Marco のコメントより)
ところで、shellcheck へのポインタをありがとうございます。これまで見たことがありませんでした。