Ich probiere Shellcheck aus .
Ich habe so etwas
basename "${OPENSSL}"
und ich bekomme folgenden vorschlag
Use parameter expansion instead, such as ${var##*/}.
Aus praktischer Sicht sehe ich keinen Unterschied
$ export OPENSSL=/opt/local/bin/openssl
$ basename ${OPENSSL}
openssl
$ echo ${OPENSSL##*/}
openssl
Da dies basename
in den POSIX-Spezifikationen enthalten ist , gibt es keinen Grund, warum dies die beste Vorgehensweise sein sollte. Irgendein Hinweis?
csh
. Ich denke,csh
ist dann nicht POSIX.Antworten:
Es geht nicht um Effizienz, sondern um Korrektheit.
basename
Begrenzt die ausgegebenen Dateinamen mit Zeilenumbrüchen. Wenn Sie nur einen Dateinamen übergeben, wird in der Regel eine abschließende neue Zeile in die Ausgabe eingefügt. Da Dateinamen möglicherweise selbst Zeilenumbrüche enthalten, ist es schwierig, diese Dateinamen korrekt zu behandeln.Es wird weiter durch die Tatsache erschwert , dass die Menschen in der Regel verwenden ,
basename
wie folgt aus :"$(basename "$file")"
. Das macht die Sache noch schwieriger, weil$(command)
Streifen alle hinteren Zeilenumbrüche auscommand
. Betrachten Sie den unwahrscheinlichen Fall,$file
der mit einem Zeilenumbruch endet. Dannbasename
wird eine zusätzliche Newline hinzufügen, aber"$(basename "$file")"
wird der Streifen beiden Zeilenumbrüche, Sie mit einem falschen Dateinamen zu verlassen.Ein weiteres Problem
basename
ist, dass wenn$file
mit a beginnt-
(Bindestrich oder Minus) begonnen wird, dies als Option interpretiert wird. Dieser ist leicht zu beheben:$(basename -- "$file")
Die robuste Art der Verwendung
basename
ist folgende:Eine Alternative ist die Verwendung
${file##*/}
, die einfacher ist, aber eigene Fehler aufweist. Insbesondere ist es falsch , in den Fällen , in denen$file
ist/
oderfoo/
.quelle
$file
istfoo/
? Was ist, wenn es ist/
?basename
Ansatz immerhin besser ist, so abgedreht er auch ist. Die besten Alternativen, die ich finden kann, sind${${${file}%%/#}##*/}
und[[ $file =~ "([^/]*)/*$" ]] && printf "%s" $match[1]
, die beide zsh-spezifisch sind und die beide nicht/
richtig handhaben .Die entsprechenden Zeilen in
shellcheck
‚s - Quellcode sind:Es gibt keine explizite Erklärung, aber basierend auf dem Namen der function (
checkNeedlessCommands
) sieht es so aus, als ob @jordanm ganz richtig ist und Sie vermeiden, einen neuen Prozess zu forken.quelle
dirname
,basename
,readlink
Etc (dank @Marco - Fehler behoben wird) Portabilität Probleme schaffen kann , wenn die Sicherheit wichtig wird (erfordert Sicherheit des Pfades). Viele Systeme (wie Fedora Linux) platzieren es auf,/bin
während andere (wie Mac OSX) es auf platzieren/usr/bin
. Dann gibt es Bash unter Windows, zB cygwin, msys und andere.Es ist immer besser, wenn es geht, pur zu bleiben.(per @Marco Kommentar)Übrigens, danke für den Hinweis auf Shellcheck, das habe ich noch nie gesehen.
quelle
dirname
. 3) Grundlegende Kerndienstprogramme sollten sich im PATH befinden, wo immer sie gespeichert sind. Ich habe noch kein System gesehen, dasbasename
nicht im PATH enthalten war. 4) Vorausgesetzt, Bash ist verfügbar, ist dies ein Portabilitätsproblem. Es ist immer besser, sich von bash fernzuhalten und eine POSIX-Shell zu verwenden, wenn Portabilität erforderlich ist.posix
und nichtbash
. Ich finde keinen Indikator dafür, dass das OP eine Bash-Lösung erfordert. Ihre Aussage "Es ist immer besser, rein zu bleiben, Bash" ist einfach falsch, es tut mir leid.