Дело не в эффективности, а в правильности. basename
использует новые строки для разграничения имен файлов, которые он печатает. В обычном случае, когда вы передаете только одно имя файла, он добавляет завершающий символ новой строки в свой вывод. Поскольку имена файлов могут содержать символы новой строки, это затрудняет правильную обработку этих имен файлов.
Это осложняется еще и тем , что люди , как правило , используют basename
так: "$(basename "$file")"
. Это делает вещи еще более сложными, потому что $(command)
убирает все завершающие символы новой строки command
. Рассмотрим маловероятный случай, который $file
заканчивается новой строкой. Затем basename
добавит дополнительную новую строку, но "$(basename "$file")"
удалит обе строки, оставив вас с неправильным именем файла.
Другая проблема в 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/
.