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


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



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.


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.


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.


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

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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.