Dlaczego tylda (~) nie rozwija się w podwójnych cudzysłowach?

54

Zgodnie z tą odpowiedzią i moim własnym zrozumieniem tylda rozwija się do katalogu domowego:

$ echo ~
/home/braiam

Teraz, ilekroć chcę, aby rozszerzenie powłoki działało, tzn. Używa takich nazw zmiennych $FOOi nie łamie z powodu nieoczekiwanych znaków, takich spacji itp., Należy użyć podwójnych cudzysłowów ":

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

Dlaczego to rozszerzenie nie działa z tyldą?

$ echo ~/some/path
/home/braiam/some/path
$ echo "~/some/path"
~/some/path
Braiam
źródło
3
Zauważ również, że ma to niespójność przy podawaniu argumentu programu w wierszu polecenia, który w przypadku argumentu polecenia --path ~/myfilerozwija się, ale --path=~/myfilenie zmienia.
Ángel
Powiązane: Czy ~ zawsze równa się $ HOME
Stéphane Chazelas 18.08.16
Odmianą tego motywu jest unix.stackexchange.com/questions/279565 .
JdeBP

Odpowiedzi:

45

Powodem, ponieważ w podwójnych cudzysłowach tylda ~nie ma specjalnego znaczenia, jest traktowana jako dosłowna.

POSIX definiuje cudzysłowy jako:

Umieszczanie znaków w podwójnych cudzysłowach („”) zachowuje dosłowną wartość wszystkich znaków w podwójnych cudzysłowach, z wyjątkiem znaków znaku dolara, cudzysłowu i odwrotnego ukośnika,

...

Wniosek powinien dopilnować, aby podwójny cudzysłów poprzedzony był odwrotnym ukośnikiem, który ma być zawarty w podwójnym cudzysłowie. Parametr „@” ma specjalne znaczenie w cudzysłowach

Z wyjątkiem $, `, \i @, inne znaki są traktowane jako dosłowne wewnątrz cudzysłowach.

Cuonglm
źródło
9
W takim przypadku myślę, że powinieneś użyć $HOME.
Seth
11
Albo nie możesz po prostu zacytować ~, na przykładls -l ~/"My Documents"
Andrew Medico
Jest to bardzo nieintuicyjne. Z jakiego powodu zdecydowali się to zrobić? (Ta odpowiedź w rzeczywistości nie podaje przyczyny, a jedynie wskazuje na standard, ale przypuszczalnie norma została napisana w ten sposób z jakiegoś powodu .)
iconoclast
1
@iconoclast, jeśli naprawdę chcesz „dlaczego zostały zaimplementowane w ten sposób”, przeczytaj odpowiedź Stephane'a .
Braiam
2
Więc @iconoclast, dlaczego jest niebo jest niebieskie? :) :) :)
Jesse Chisholm
32

Rozwinięcie tyldy definiowane jest przez POSIX jako:

„Przedrostek tyldy” składa się z niecytowanego znaku <tilde> na początku słowa, po którym następują wszystkie znaki poprzedzające pierwszy bez cudzysłowu <slash> w słowie lub wszystkie znaki w słowie, jeśli nie ma < slash>. W przydziale można użyć wielu prefiksów tyldy: [...] po <znaku równości> przypisania, po każdym nie cytowanym <kolonie> lub obu. [...] Jeśli żaden z znaków w prefiksie tyldy nie jest cytowany, znaki w prefiksie tyldy po znaku <tyldy> są traktowane jako możliwa nazwa logowania z bazy danych użytkowników. [...] Jeśli nazwa logowania ma wartość NULL (to znaczy, że przedrostek tyldy zawiera tylko tyldę), przedrostek tyldy jest zastępowany wartością zmiennej HOME. Jeśli HOME jest wyłączone, wyniki nie są określone. [...]

Tak więc najkrótsza odpowiedź brzmi „ponieważ tak jest zdefiniowane”: zacytowanie dowolnego znaku w prefiksie, w tym znaku „ ~,” wstrzymuje rozwinięcie.

Definiuje także rozwinięcie jako zawsze skutkujące pojedynczym słowem, więc cytowanie byłoby niepotrzebne:

Nazwę ścieżki wynikającą z rozwinięcia tyldy należy traktować tak, jakby była cytowana, aby zapobiec jej zmianie przez podział pola i rozwinięcie nazwy ścieżki.

Tam, gdzie niektóre ścieżki wymagają cytowania, a reszta to przedrostek tyldy, możesz od razu połączyć rozwinięcie tyldy i zwykłe cytowanie:

$ cat ~/"file name with spaces"

Mówiąc szerzej „dlaczego”: ponieważ nie można sobie wyobrazić dzielenia słów ~, powinno to być zachowanie domyślne, zamiast wymagać cytowania. Ponieważ nie ma potrzeby cytowania, nadanie ~specjalnego znaczenia w cudzysłowie byłoby niepotrzebną komplikacją. I oczywiście przyczyny historyczne oznaczają, że nie można go teraz zmienić, nawet jeśli byłoby to pożądane.

Michael Homer
źródło
Zgodnie z tym przewodnikiem bash , rozwinięcie tyldy następuje przed separacją białych znaków. Czy istnieje sposób na bezpieczne wykonanie interpretacji tyldy, nawet jeśli w katalogu domowym jest spacja? Zazwyczaj robiłbyś takie rzeczy "".
Lucretiel,
Rozszerzenie jest jednym słowem; patrz drugi cytowany fragment w odpowiedzi.
Michael Homer,
23

~ powstaje w powłoce C na długo przed dodaniem jej do powłoki Korna, a następnie dodaniem do specyfikacji powłoki POSIX.

W powłoce C ~znajdował się operator globowania (rozwinięty przez tę samą procedurę jak *.txtna przykład ta rozwijająca się ), więc podobnie jak reszta globowania nie była wykonywana wewnątrz podwójnych cudzysłowów.

Stéphane Chazelas
źródło
11

Chociaż nie odpowiada to na pytanie, dlaczego jest tak zaprojektowany, $HOMEzamiast tego używasz go, jeśli musisz go zastąpić, ponieważ tak właśnie ~działa.

$ echo "$HOME/some/path"
/home/braiam/some/path
stawy
źródło
6
to nie działa z~otheruser
Johannes Kuhn
2
To prawda, ale możesz zrobić: THEM = ~ inny użytkownik, a następnie użyj „$ THEM / some / path”
melduje
1
Obejście problemu ~otheruserpokazuje, jak złym pomysłem było traktować ~inaczej niż zmienne i inne rzeczy, które są rozwinięte w podwójnych cudzysłowach.
iconoclast