Próbuję sprawdzić shellcheck .
Mam coś takiego
basename "${OPENSSL}"
i otrzymuję następującą sugestię
Use parameter expansion instead, such as ${var##*/}.
Z praktycznego punktu widzenia nie widzę różnicy
$ export OPENSSL=/opt/local/bin/openssl
$ basename ${OPENSSL}
openssl
$ echo ${OPENSSL##*/}
openssl
Ponieważ basename
jest to specyfikacja POSIX , nie mam powodu, dla którego powinna to być najlepsza praktyka. Jakaś wskazówka?
csh
. Chybacsh
nie jest to wtedy POSIX.Odpowiedzi:
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 liniicommand
. Rozważ mało prawdopodobny przypadek, który$file
kończy się nową linią. Następniebasename
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: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/
lubfoo/
.źródło
$file
jestfoo/
? Co jeśli to jest/
?basename
podejście jest jednak lepsze, jakkolwiek jest hackerskie. Najlepsze alternatywy, jakie mogę wymyślić, to${${${file}%%/#}##*/}
i[[ $file =~ "([^/]*)/*$" ]] && printf "%s" $match[1]
oba są specyficzne dla Zsh i żadna z nich nie obsługuje się/
poprawnie.Odpowiednie linie w
shellcheck
„s kodu źródłowego są:Nie podano wyraźnego wyjaśnienia, ale na podstawie nazwy funkcji (
checkNeedlessCommands
) wygląda na to, że @jordanm ma rację i sugeruje unikanie tworzenia nowego procesu.źródło
dirname
,basename
,readlink
Etc (dzięki @Marco - jest to poprawione) może stworzyć problemy przenośności gdy bezpieczeństwo staje się ważnym (wymagające zabezpieczenia toru). Wiele systemów (takich jak Fedora Linux) umieszcza go w,/bin
podczas gdy inne (jak Mac OSX) umieszczają go w/usr/bin
. Potem jest Bash na Windowsie, np. Cygwin, msys i inne.Zawsze lepiej pozostać czystym Bash, jeśli to możliwe.(na komentarz @Marco)BTW, dzięki za wskaźnik do shellcheck, nie widziałem tego wcześniej.
źródło
dirname
. 3) Podstawowe narzędzia podstawowe powinny znajdować się w ścieżce PATH, gdziekolwiek są przechowywane. Nie widziałem jeszcze systemu, któregobasename
nie było w ŚCIEŻCE. 4) Zakładanie, że bash jest dostępny, to problem z przenośnością. Zawsze lepiej trzymać się z daleka od basha i używać powłoki POSIX, gdy wymagana jest przenośność.posix
a niebash
. Nie mogę znaleźć żadnego wskaźnika, że OP wymaga rozwiązania bash. Twoje stwierdzenie „Zawsze lepiej pozostać czystym Bash” jest po prostu błędne, przepraszam.