Es geht nicht um Effizienz, sondern um Korrektheit. basenameBegrenzt 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 , basenamewie folgt aus : "$(basename "$file")". Das macht die Sache noch schwieriger, weil $(command)Streifen alle hinteren Zeilenumbrüche aus command. Betrachten Sie den unwahrscheinlichen Fall, $fileder mit einem Zeilenumbruch endet. Dann basenamewird 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 basenameist, dass wenn $filemit a beginnt- (Bindestrich oder Minus) begonnen wird, dies als Option interpretiert wird. Dieser ist leicht zu beheben:$(basename -- "$file")
Die robuste Art der Verwendung basenameist 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 $fileist /oder foo/.