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