~
в кавычках остается буквальным ~
. Соответствующая часть справочного руководства Bash начинается с
Если слово начинается с символа кавычки без кавычек (~
),…
Чтобы увидеть разницу, сравните:
file="~/.gitconfig"
echo "$file"
file=~/".gitconfig"
echo "$file"
В вашем первом примере $(…)
работает первым, а в его контексте ~
кавычек. Таким образом, он расширяется, как вы ожидаете.
Ваш $file
, когда он «не работает», содержит буквальный символ ~
. Стандарт POSIX гласит:
Порядок расширения слова должен быть следующим:
Расширение тильды […], расширение параметров […], подстановка команд […] и арифметическое расширение […] должны выполняться от начала до конца. [...]
Поскольку раскрытие тильды выполняется до раскрытия параметра, переменная, которая расширяется до ~/something
, не расширяется дальше по правильному пути.
Помните, ~
или ~/
является особенным для вашей оболочки в некоторых случаях, но для (почти?) любой другой инструмент это недопустимый путь. Когда это работает, это потому, что оболочка сначала выполняет свою "магию", а другой инструмент видит уже расширенный путь (например, /Users/jord
).
Обратите внимание, что в последнем примере расширение тильды не работает, вы все равно получаете литерал ~
и оболочке уже слишком поздно что-то делать без дополнительных уловок (например, eval
). dirname
не жалуется, потому что работает со строками. Ему все равно, является ли данный путь допустимым, существующим и т.д. В основном он просто ищет последний компонент без косой черты и отбрасывает его с завершающими косыми чертами (если они есть).
Смотрите также этот ответ.