Nie chodzi o wydajność - chodzi o poprawność. basename
używa znaku nowej linii do określenia nazw plików, które drukuje. W zwykłym przypadku, gdy przekazujesz tylko jedną nazwę pliku, dodaje on końcowy znak nowej linii do wyniku. Ponieważ nazwy plików mogą zawierać same znaki nowej linii, utrudnia to prawidłową obsługę tych nazw plików.
To dodatkowo komplikuje fakt, że ludzie zwykle wykorzystać basename
tak: "$(basename "$file")"
. To sprawia, że wszystko jest jeszcze trudniejsze, ponieważ $(command)
usuwa wszystkie końcowe znaki nowej linii command
. Rozważ mało prawdopodobny przypadek, który $file
kończy się nową linią. Następnie basename
doda nową "$(basename "$file")"
linię , ale usunie obie linie, pozostawiając niepoprawną nazwę pliku.
Innym problemem basename
jest to, że jeśli $file
zaczyna się od -
(myślnik aka minus), będzie to interpretowane jako opcja. Ten jest łatwy do naprawienia:$(basename -- "$file")
Solidny sposób użycia basename
jest następujący:
# 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%??}"
Alternatywą jest użycie ${file##*/}
, które jest łatwiejsze, ale ma własne błędy. W szczególności jest to złe w przypadkach, gdy $file
jest /
lub foo/
.