Справа не в ефективності - це в правильності. 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/
.