Es geht nicht um Effizienz, sondern um Korrektheit. basename
Begrenzt die ausgegebenen Dateinamen mit Zeilenumbrüchen. Wenn Sie nur einen Dateinamen übergeben, wird in der Regel eine abschließende neue Zeile in die Ausgabe eingefügt. Da Dateinamen möglicherweise selbst Zeilenumbrüche enthalten, ist es schwierig, diese Dateinamen korrekt zu behandeln.
Es wird weiter durch die Tatsache erschwert , dass die Menschen in der Regel verwenden , basename
wie folgt aus : "$(basename "$file")"
. Das macht die Sache noch schwieriger, weil $(command)
Streifen alle hinteren Zeilenumbrüche aus command
. Betrachten Sie den unwahrscheinlichen Fall, $file
der mit einem Zeilenumbruch endet. Dann basename
wird eine zusätzliche Newline hinzufügen, aber "$(basename "$file")"
wird der Streifen beiden Zeilenumbrüche, Sie mit einem falschen Dateinamen zu verlassen.
Ein weiteres Problem basename
ist, dass wenn $file
mit a beginnt-
(Bindestrich oder Minus) begonnen wird, dies als Option interpretiert wird. Dieser ist leicht zu beheben:$(basename -- "$file")
Die robuste Art der Verwendung basename
ist folgende:
# 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%??}"
Eine Alternative ist die Verwendung ${file##*/}
, die einfacher ist, aber eigene Fehler aufweist. Insbesondere ist es falsch , in den Fällen , in denen $file
ist /
oder foo/
.