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