Почему mkdir завершается ошибкой (такого файла или каталога нет) в сценарии с BIN_DIR = «~ / bin /»?


10

Почему команда mkdir завершается с ошибкой: «Нет такого файла или каталога»?

#!/bin/bash

set -e

BIN_DIR="~/bin/"

if [ ! -d "$BIN_DIR" ]; then
  mkdir "$BIN_DIR"
fi

Ответы:


11

Сообщение об ошибке появляется, потому что тильда заключена ~в кавычки, как описано в ответе Занны . Если вы хотите использовать ~, соответствующая часть скрипта должна быть:

BIN_DIR=~/bin/

Если по какой-либо причине вы хотите заключить строку в кавычки, вы можете использовать переменную окружения $HOME:

BIN_DIR="$HOME/bin/"

На мой взгляд, второй подход - лучшая практика.


6
Нет ничего плохого в использовании ~в скриптах. он работает точно так же, как и в командной строке. Проблема в том, что цитирование блокирует расширение тильды, как объяснено в ответе Занны .
тердон

@terdon, я согласен. Но я не говорил, что что-то не так, но это лучшая идея, потому что вы должны уделять меньше внимания.
pa4080

5
Но здесь нет абсолютно никакой разницы между командной строкой и скриптом. Тот факт, что это в сценарии, совершенно не имеет значения, у вас будет точно такая же ошибка в командной строке. Проблема заключается в цитировании, а не в том, что это в сценарии.
тердон

Хотя это совершенно верно, также верно, что использование $HOMEв скриптах - хорошая идея.
десерт

3
@ pa4080 Можете ли вы объяснить, почему вы считаете, что лучше расширять, $HOMEчем использовать расширение тильды? Единственное объяснение, которое вы дали, - это сказать: «это лучшая идея, потому что вам следует уделять меньше внимания». Я понятия не имею, что это значит. Можете ли вы объяснить это в редактировании? Без этого нет ничего, что поддерживало бы ваш ответ, так что, несомненно, оно принадлежит ему. Тильда расширение было предусмотрено POSIX для достаточно, а теперь и hashbang линии скрипта является , #!/bin/bashпоэтому я полагаю , портативность не является причиной.
Элия ​​Каган

23

Это не работает, потому что ~цитируется. Двойные кавычки " подавляют расширение тильды . Нет каталога с буквальным именем ~/bin. Как объяснено в man bash(выделение мое):

Расширение Тильды

Если слово начинается с символа кавычки без кавычек (`~ '), все символы, предшествующие первой косой черте без кавычек (или все символы, если нет косой черты без кавычек), считаются префиксом тильды. Если ни один из символов в префиксе тильды не указан в кавычках, символы в префиксе тильды, следующие за тильдой, рассматриваются как возможное имя для входа. Если это имя входа является пустой строкой, тильда заменяется значением параметра оболочки HOME. Если HOME не задан, вместо него подставляется домашний каталог пользователя, выполняющего оболочку. В противном случае префикс тильды заменяется домашним каталогом, связанным с указанным именем входа.

Вы можете удалить кавычки , так ~как это единственный символ в пути ~/bin, который заставит оболочку выполнить расширение, и в этом случае мы хотим расширение. Оболочки не будут выполнять какие - либо дополнительные разложения на результате тильды, по крайней мере , в Bash 4 , который все текущие или удаленно последние версии Ubuntu есть . Так что, даже если ваш домашний каталог содержит необычные символы, такие как пробелы, это нормально.

Или вы можете использовать $HOMEвместо из ~, так как расширение параметр не подавляется в двойных кавычках, только одинарные кавычки . Двойные кавычки действительно убедитесь , что расширенное значение не сам по себе с учетом любых дальнейших расширений, поэтому разбиение слов или расширение файла не произойдет. Так же $HOMEработает даже со странными именами домашних каталогов, если вы сохраняете двойные кавычки.


Согласно этому утверждению «расширение параметра не подавляется двойными кавычками, только одинарными кавычками» : вывод cd '~'is -bash: cd: ~: No such file or directory.
pa4080

2
@ pa4080 Расширение ~не является частью расширения параметра.
Бармар
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.