Чому tilde (~) не розширюється всередині подвійних лапок?


54

Відповідно до цієї відповіді та мого власного розуміння, тильда поширюється на домашній каталог:

$ echo ~
/home/braiam

Тепер, коли я хочу, щоб розширення оболонки працювало, тобто використовуючи назви змінних, таких як $FOO, і не порушувати належних несподіваних символів, таких пробілів тощо, слід використовувати подвійні лапки ":

$ FOO="some string with spaces"
$ BAR="echo $FOO"
$ echo $BAR
echo some string with spaces

Чому це розширення не працює з тильдом?

$ echo ~/some/path
/home/braiam/some/path
$ echo "~/some/path"
~/some/path


3
Також зауважте, що це має непослідовність при наданні програмного аргументу в командному рядку, що в командному аргументі --path ~/myfileрозширюється, але --path=~/myfileне є.
Ángel



Варіант цієї теми - unix.stackexchange.com/questions/279565 .
JdeBP

Відповіді:


45

Причина, тому що всередині подвійних цитат тильда ~не має особливого значення, вона трактується як буквальна.

POSIX визначає подвійні котирування як:

Введення символів у подвійні лапки ("") має зберігати буквальне значення всіх символів у подвійних лапках, за винятком знаків долара, зворотного котирування та зворотньої косої риси,

...

Додаток повинен забезпечити, щоб подвійне котирування передувало зворотному косому рису, яке буде включено до подвійних лапок. Параметр "@" має особливе значення всередині подвійних лапок

Крім $, `, \і @, інші символи розглядаються як буквальний в подвійних лапках.


9
У такому випадку я думаю, ви повинні використовувати $HOME.
Сет

11
Або ви можете просто не процитувати ~, наприкладls -l ~/"My Documents"
Andrew Medico

Це дуже неінтуїтивно. З якої причини вони вирішили це зробити? (Ця відповідь насправді не дає причини, а скоріше лише вказує на стандарт, але, мабуть, стандарт був написаний саме так з причини .)
iconoclast

1
@iconoclast, якщо ви дійсно хочете "чому вони реалізовані таким чином", прочитайте натомість відповідь Стефана .
Брайам

2
Так, @iconoclast, чому це небо блакитне? :) :) :)
Джессі Чизгольм

32

Розширення Tilde визначається POSIX як:

"Префікс тильди" складається з нецитованого символу <tilde> на початку слова, за яким слідують усі символи, що передують першому котируваному <косому слову> у слові, або всі символи в цьому слові, якщо немає < коса> У призначенні можна використовувати кілька префіксів тильди: [...] після <equals-sign> призначення, після будь-якого без котировки <colon> або обох. [...] Якщо жоден із символів префікса tilde не цитується, символи в префіксі tilde після <tilde> трактуються як можливе ім’я для входу з бази даних користувача. [...] Якщо ім'я для входу є нульовим (тобто префікс tilde містить лише тильду), префікс tilde замінюється значенням змінної HOME. Якщо HOME не встановлено, результати не визначені. [...]

Отже, найкоротша відповідь - "тому, що визначено саме так": цитування будь-якого з символів у префіксі, включаючи ~, пригнічує розширення.

Він також визначає розширення як завжди, що призводить до одного слова, тому цитування було б зайвим:

Ім'я шляху, що виникає внаслідок розширення тильди, розглядається так, ніби цитується, щоб запобігти його зміні розбиттям поля та розширенням імені шляху.

Там, де частина шляху вимагає цитування, а решта - префікс тильди, ви можете поєднувати розширення тильди та звичайне цитування прямо:

$ cat ~/"file name with spaces"

Щодо ширшого "чому": оскільки немає можливості використовувати для розбиття слів ~, це має бути поведінкою за замовчуванням, а не вимагати її цитування. Тому що немає необхідності цитувати це, надання ~особливого значення всередині цитат було б зайвим ускладненням. І, звичайно, історичні причини означають, що його зараз не можна змінити, навіть якщо це було б бажано.


Згідно з цим керівництвом Баша, розширення тильда відбувається перед розділенням пробілів. Чи є спосіб безпечно виконати розширення тильди, навіть якщо в домашньому каталозі є пробіли? Звичайно, звичайно, ви б робили подібні речі "".
Лукретьєль

Розширення - це одне слово; дивіться у відповіді другий процитований уривок.
Майкл Гомер

23

~ бере свій початок у C-оболонці, задовго до того, як вона була додана до оболонки Korn та пізніше додана до специфікації оболонки POSIX.

У C-оболонці ~був оператор глобалізації (розширений тим самим розпорядженням, що і розширюється, *.txtнаприклад), тому, як і решта глобулінгу, не виконувались подвійні лапки.


11

Хоча це не відповідає, чому він створений таким чином, ви $HOMEзамість цього використовуєте, якщо вам потрібно замінити, оскільки це, по суті, те, що ~робить.

$ echo "$HOME/some/path"
/home/braiam/some/path

6
з цим не працює~otheruser
Йоганнес Кун

2
Правда, але ви можете зробити: THEM = ~ otheruser тоді використовуйте "$ THEM / some / path"
melds

1
Вирішення проблеми ~otheruserпоказує, яка погана ідея полягала в тому, щоб трактувати ~інакше, ніж до змінних та інших речей, розгорнутих всередині подвійних лапок.
іконоборство
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.