Путаница интерполяции путаницы

414
jordelver

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

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

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

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

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

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

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

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

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

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

1
Почему `echo" $ (dirname - "$ file") "`? Почему не просто `dirname -" $ file "`? Kamil Maciorowski 5 лет назад 0
Скопируйте и вставьте из другого примера :) jordelver 5 лет назад 0
Пожалуйста, посмотрите это: [Что не так с `echo $ (stuff)` или `echo \` stuff \ ``?] (Https://superuser.com/q/1352850/432690) Kamil Maciorowski 5 лет назад 1

1 ответ на вопрос

3
Kamil Maciorowski

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

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

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

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

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

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

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

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

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

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

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

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

Спасибо. Это имеет смысл теперь, когда вы так хорошо это объяснили. jordelver 5 лет назад 0