Dlaczego nie mogę cd do cytowanej tyldy ('~')?

32

Piszę swój pierwszy skrypt, więc jestem pewien, że jest to podstawowe pytanie, ale czy ktoś mógłby mi wyjaśnić, dlaczego:

cd ~
cd bin
cd ~/bin
cd 'bin'

Ale nie

cd '~'
cd '~/bin'

Muszę przejść cddo ścieżki katalogu ze spacją w jednej z nazw katalogów, więc potrzebuję cudzysłowów (to Windows Program Filespod winem). Mogę obejść to za pomocą dwóch cdpoleceń, ale dlaczego nie mogę wstawiać ~cudzysłowów?

Po wpisaniu cd '~'(lub cd "~") otrzymam:

bash: cd: ~: No such file or directory
B.Tanner
źródło
29
Zadaj sobie to pytanie : jeśli nie zadziałałoby w ten sposób, w jaki sposób uzyskałbyś cdkatalog o nazwie ~?
Jörg W Mittag
2
Krótko mówiąc, jeśli piszesz skrypt, powinieneś raczej używać ścieżek bezwzględnych i unikać wszystkich cd. Użycie zmiennych do przechowywania ścieżek nie chcesz wpisywać wiele razy, na przykładpf=~/.wine/drive_c/Program\ Files/; cp /path/to/file "$pf"
deser
8
@jamesqf: Dlaczego rozsądny system miałby lepiej wiedzieć ode mnie, jak chcę nazwać moje pliki i katalogi? Nigdy też nie rozumiałem, dlaczego Unix poszedł z magiczną wewnątrzpasmową sygnalizacją separatorów komponentów ścieżki i terminatorów ścieżki. Co jest nie tak z plikiem / katalogiem o nazwie /lub NUL?
Jörg W Mittag
3
@ JörgWMittag prawdopodobniecd ./~
k_g
2
@jamesqf Należy zauważyć, że historycznie uniksowe systemy plików dopuszczały dowolny znak w nazwie pliku z wyjątkiem „/” (separator ścieżki) i „\ 0” (NUL - znak zakończenia łańcucha) - jak zauważa Jorg. Brak innych ograniczeń. Było wiele implementacji systemu plików Unix, więc wprowadzenie ograniczeń w jednym z nich złamałoby kompatybilność i zwiększyło złożoność - i byłoby postrzegane jako „dziwne”! Rozszerzenie „~” zostało wprowadzone stosunkowo niedawno w csh, a szerzej w bash, pliki / katalogi z znakami „~” nie są nieznane (np. Mój_plik ~ jako kopia zapasowa dla mojego_pliku).
SusanW,

Odpowiedzi:

78

Jak zauważył @karel w swojej odpowiedzi, ~jest znakiem specjalnym i został rozszerzony przez Basha do katalogu domowego bieżącego użytkownika. Zobacz instrukcję Basha dotyczącą „Rozszerzenia tyldy” lub wyszukaj nagłówek „Rozszerzenia tyldy” na stronie podręcznika ( man bash).

Jakikolwiek cytat wokół ~zapobiega temu rozszerzeniu tyldy.


Aby odpowiedzieć na pytanie, w jaki sposób nadal można go używać do cdkatalogu ze spacjami w jego nazwie, istnieje kilka alternatyw:

  • Zamiast tego pomiń cytaty i użyj spacji ułamkowych:

    cd ~/foo/spaces\ are\ cool/bar
  • Cytuj resztę ścieżki, ale pomiń je wokół tyld i pierwszego ukośnika:

    cd ~/"foo/spaces are cool/bar"

    Jak widzisz, możesz łączyć cytowane i niecytowane ciągi w Bash, po prostu pisząc je obok siebie, bez odstępów między nimi.

  • Użyj zmiennej środowiskowej $HOMEzamiast tyldy, która wciąż jest rozwijana w „podwójnych cudzysłowach” (ale nie „pojedynczych cudzysłowach”):

    cd "$HOME/foo/spaces are cool/bar"
Bajt Dowódca
źródło
3
@ rexkogitans ~'/...'nie będzie działać i nie jest tym, co ma ta odpowiedź. ~/'...'lub ~/"..."zadziała.
hvd
tld; dr: ponieważ
taka jest
@hvd dzięki. Naprawiono literówkę. Jest to najbardziej kompletna odpowiedź, a także wyjaśnia, jak rozwiązać to, co PO chce zrobić. ~/'path'jest droga.
rexkogitans
1
@hvd tylko trochę ciekawości, dlaczego nie miałoby ~'/...'działać? Ukośnik nie jest znakiem specjalnym, więc wydaje się, że powinien działać zarówno wewnątrz, jak i poza cytatami.
Kodos Johnson
6
@KodosJohnson Zajrzyj do strony podręcznika Bash na temat „Tilde Expansion”. Odpowiedni akapit tego jest również cytowany w odpowiedzi na deser poniżej. TL; DR: Rozwinięcie tyldy ma miejsce, jeśli pierwszy znak w słowie jest niecytowaną tyldą, wówczas wszystko między tą tyldą a następnym niecytowanym ukośnikiem jest uważane za „przedrostek tyldy”. Jeśli ten prefiks nie jest prawidłową rzeczą, np. +, -, liczba lub nazwa użytkownika (cytaty też nie są dozwolone), interpretacja kończy się niepowodzeniem i pojawia się literalny znak ~.
Bajt Dowódca
17

~ jest znakiem specjalnym, który jest interpretowany przez powłokę jako katalog domowy zalogowanego użytkownika. „~” jest interpretowane przez powłokę jako dosłowny znak ~, a nie jako katalog domowy zalogowanego użytkownika, ponieważ umieszczenie ciągu wewnątrz dwóch pojedynczych znaków cudzysłowu powoduje, że ciąg ten jest interpretowany jako dosłowny ciąg tekstowy.

Karel
źródło
~nie jest aliasem w tym sensie, bashże je interpretuje: Aliasy pozwalają na zastąpienie łańcucha słowem, gdy jest ono używane jako pierwsze słowo prostej komendy. . Jak wyjaśniam w mojej odpowiedzi poniżej, jest to raczej rozszerzenie.
deser
15

Jest to bashfunkcja o nazwie Tilde Expansion . Powołując się man bash:

Jeśli słowo zaczyna się od niecytowanego znaku tyldy (`~ '), wszystkie znaki poprzedzające pierwszy niecytowany ukośnik (lub wszystkie znaki, jeśli nie ma cudzysłowu) są uważane za przedrostek tyldy. Jeśli żaden z znaków w prefiksie tyldy nie jest cytowany, znaki w prefiksie tyldy po tyldie są traktowane jako możliwa nazwa logowania. Jeśli ta nazwa logowania jest łańcuchem zerowym, tylda jest zastępowana wartością parametru powłoki HOME. Jeśli HOME jest wyłączone, katalog domowy użytkownika wykonującego powłokę jest zastępowany.

Aby rozwinięcie działało, znak tyldy ~musi być niecytowany, w przeciwnym razie znak jest traktowany dosłownie i cdkończy się niepowodzeniem, jeśli ~w bieżącym katalogu nie ma nazwanego katalogu. Zobacz tę entuzjastyczną odpowiedź na wyjaśnienie cytowania w bash. Jeśli chcesz zacytować część ścieżki, możesz:

  1. podaj co najmniej znaki wymagające pojedynczego cudzysłowu, np

    ~/dir' 'with' 'spaces/

    lub

    ~/'dir with spaces/'
  2. podaj przynajmniej znaki, które wymagają cudzysłowu, np

    ~/dir" "with" "spaces/

    lub

    ~/"dir with spaces/"
  3. cytuj tylko znaki wymagające cudzysłowu, np

    ~/dir\ with\ spaces/

Rozszerzenie Tilde ma kilka ciekawszych funkcji, np .:

  • ~+rozwija się do wartości PWD, tj. bieżącego katalogu roboczego
  • ~-rozwija się do wartości OLDPWD, tj. poprzedniego katalogu roboczego
  • ~john rozwija się do katalogu domowego powiązanego z nazwą logowania „John”
deser
źródło
Nawiasem mówiąc, „przepełnianie” również odwrotnymi ukośnikami jest w porządku; np $ touch a; cd \a. (Myślałem, że może to mieć problemy cd \n, ale eksperymenty przynajmniej w mojej wersji bashsugerują, że działa dobrze.)
LSpice
1

Przeglądaj za pomocą echopolecenia

Najłatwiejszym sposobem sprawdzenia, jak działa bash, jest echopolecenie. W przypadku ~użycia:

$ echo ~
/home/rick
$ echo '~'
~
$ echo "~"
~
$ echo `~`
bash: /home/rick: Is a directory

Jak widać, gdy pojedynczego cudzysłowu lub podwójnych cudzysłowów wokół ~niego jest interpretowany dosłownie jako ciąg i nie jest rozwijany jako zmienna. Kiedy używasz backticks (`), jest on wykonywany jako polecenie i generuje komunikat o błędzie.

WinEunuuchs2Unix
źródło