Из руководства по Bash (man bash
):
Command Substitution Command substitution allows the output of a command to replace the command name. There are two forms: $(command) or `command` Bash performs the expansion by executing command in a subshell environment and replacing the command substitution with the standard output of the command, with any trailing newlines deleted. Embedded newlines are not deleted, but they may be removed during word splitting. The command substitution $(cat file) can be replaced by the equivalent but faster $(< file).
(Это справедливо для всех Bourne-подобных оболочек, т.е. sh
, ksh
, zsh
, bash
и др, а zsh
также способен перехватывать таким образом данные со встроенными символами NUL)
Команда
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
присвоит переменной basedir
имя каталога, в котором находится скрипт (при этом все обратные слеши будут заменены на прямые). Любые ошибки, предупреждения или другие диагностические сообщения, которые выводятся в стандартный поток ошибок, будут по-прежнему отображаться на терминале ($(...)
захватывает только стандартный вывод команды).
Оболочка начнет с выполнения самой внутренней подстановки команды:
echo "$0" | sed -e 's,\\,/,g'
Вывод этой подстановки будет передан в виде строки dirname
, а вывод этой подстановки будет присвоен переменной basedir
.
Двойные кавычки нужны для того, чтобы убедиться, что не будет произведена разбивка слов или сглаживание имен файлов, иначе вы можете обнаружить, что скрипт не работает или выдает странные результаты, когда $0
(имя скрипта, включая путь, используемый для его выполнения) содержит символ пробела или символ сглаживания имен файлов (например, ?
или *
).
В целом, хорошей идеей является всегда заключать в кавычки расширения (расширения переменных, подстановки команд и арифметические расширения). См. этот вопрос и ответы на него для отличного объяснения, почему это хорошая идея.
Если скрипт был выполнен как
$ /usr/local/bin/script.sh
то basedir
получит значение /usr/local/bin
.
Или, на Cygwin:
$ bash c:\\Users\\Me\\script.sh
тогда basedir
получит значение c:/Users/Me
. Двойные обратные косые черты в командной строке в этом случае нужны только для того, чтобы убрать одинарные обратные косые черты из оболочки. Фактическое значение $0
- c:\Users\Me\script.sh
.
Другой способ сделать то же самое без использования dirname
, echo
и sed
был бы
basedir="${0//\\//}"
basedir="${basedir%/*}"