Я пытаюсь из shellcheck .
У меня что-то подобное
basename "${OPENSSL}"
и я получаю следующее предложение
Use parameter expansion instead, such as ${var##*/}.
С практической точки зрения я не вижу разницы
$ export OPENSSL=/opt/local/bin/openssl
$ basename ${OPENSSL}
openssl
$ echo ${OPENSSL##*/}
openssl
Так basename
как в спецификации POSIX , я не причина, почему это должно быть лучшей практикой. Любой намек?
csh
. Я думаю,csh
это не POSIX тогда.Ответы:
Дело не в эффективности, а в правильности.
basename
использует новые строки для разграничения имен файлов, которые он печатает. В обычном случае, когда вы передаете только одно имя файла, он добавляет завершающий символ новой строки в свой вывод. Поскольку имена файлов могут содержать символы новой строки, это затрудняет правильную обработку этих имен файлов.Это осложняется еще и тем , что люди , как правило , используют
basename
так:"$(basename "$file")"
. Это делает вещи еще более сложными, потому что$(command)
убирает все завершающие символы новой строкиcommand
. Рассмотрим маловероятный случай, который$file
заканчивается новой строкой. Затемbasename
добавит дополнительную новую строку, но"$(basename "$file")"
удалит обе строки, оставив вас с неправильным именем файла.Другая проблема в
basename
том, что если$file
начинается с-
(тире или минус), это будет интерпретироваться как опция. Это легко исправить:$(basename -- "$file")
Надежный способ использования
basename
заключается в следующем:Альтернативой является использование
${file##*/}
, которое проще, но имеет свои собственные ошибки. В частности, это неправильно в тех случаях, когда$file
есть/
илиfoo/
.источник
$file
естьfoo/
? Что если это/
?basename
подход все- таки лучше, такой же хакерский. Лучшими альтернативами, которые я могу придумать, являются${${${file}%%/#}##*/}
и[[ $file =~ "([^/]*)/*$" ]] && printf "%s" $match[1]
, оба из которых являются специфичными для zsh, и ни один из которых не обрабатывает/
правильно.Соответствующие строки в
shellcheck
«S исходный код , являются:Объяснение не дается явно, но, основываясь на имени функции (
checkNeedlessCommands
), похоже, что @jordanm совершенно прав и предлагает вам избегать разветвления нового процесса.источник
dirname
,basename
, Иreadlink
т.д. (спасибо @Marco - это исправляется) может создать проблемы с переносимостью , когда безопасность становится важной (требование безопасности пути). Многие системы (например, Fedora Linux) размещают его там,/bin
а другие (например, Mac OSX) размещают его там/usr/bin
. Тогда есть Bash на Windows, например, Cygwin, MSYS и другие.Всегда лучше оставаться чистым Башом, когда это возможно.(за комментарий @Marco)Кстати, спасибо за указатель на shellcheck, я раньше такого не видел.
источник
dirname
. 3) Базовые основные утилиты должны быть в PATH, где бы они ни хранились. Я еще не видел систему, гдеbasename
не было в PATH. 4) Если предположить, что bash доступен, это проблема переносимости. Всегда лучше держаться подальше от bash и использовать оболочку POSIX, когда требуется переносимость.posix
и нетbash
. Я не могу найти индикатор того, что ОП требует решения для bash. Ваше утверждение «всегда лучше оставаться чистым Башом» просто неправильно, извините.