1

Я пытаюсь понять интерполяцию Bash переменных.

Я хочу использовать readlink чтобы показать путь, на который указывает символическая ссылка.

Если я использую строку, это работает.

$ echo "$(readlink -- ~/.gitconfig)"
/Users/jord/.dotfiles/gitconfig

По какой-то причине это не работает, когда я пытаюсь использовать переменную вместо строки.

$ file="~/.gitconfig"
$ echo "$(readlink -- $file)"

Ничего не печатается, кроме пустой строки.

Если я сделаю то же самое, но с dirname (в качестве примера), переменная интерполяция будет работать, как я и ожидал.

$ file="~/.gitconfig"
$ echo "$(dirname -- "$file")"
~

Что я делаю неправильно?

1 ответ1

3

~ в кавычках остается буквальным ~ . Соответствующая часть справочного руководства Bash начинается с

Если слово начинается с символа кавычки без кавычек (~),…

Чтобы увидеть разницу, сравните:

file="~/.gitconfig"
echo "$file"
file=~/".gitconfig"
echo "$file"

В вашем первом примере $(…) работает первым, а в его контексте ~ кавычек. Таким образом, он расширяется, как вы ожидаете.

Ваш $file , когда он «не работает», содержит буквальный символ ~ . Стандарт POSIX гласит:

Порядок расширения слова должен быть следующим:

Расширение тильды […], расширение параметров […], подстановка команд […] и арифметическое расширение […] должны выполняться от начала до конца. [...]

Поскольку раскрытие тильды выполняется до раскрытия параметра, переменная, которая расширяется до ~/something , не расширяется дальше по правильному пути.

Помните, ~ или ~/ является особенным для вашей оболочки в некоторых случаях, но для (почти?) любой другой инструмент это недопустимый путь. Когда это работает, это потому, что оболочка сначала выполняет свою "магию", а другой инструмент видит уже расширенный путь (например, /Users/jord).

Обратите внимание, что в последнем примере расширение тильды не работает, вы все равно получаете литерал ~ и оболочке уже слишком поздно что-то делать без дополнительных уловок (например, eval). dirname не жалуется, потому что работает со строками. Ему все равно, является ли данный путь допустимым, существующим и т.д. В основном он просто ищет последний компонент без косой черты и отбрасывает его с завершающими косыми чертами (если они есть).

Смотрите также этот ответ.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .