Dlaczego mkdir zawodzi (brak takiego pliku lub katalogu) w skrypcie z BIN_DIR = „~ / bin /”?

Odpowiedzi:

11

Pojawia się komunikat o błędzie, ponieważ ~zacytowano tyldę , jak opisano w odpowiedzi Zanny . Jeśli chcesz użyć ~, odpowiednią częścią skryptu powinna być:

BIN_DIR=~/bin/

Jeśli z jakiegokolwiek powodu chcesz zacytować ciąg, możesz użyć zmiennej środowiskowej $HOME:

BIN_DIR="$HOME/bin/"

Moim zdaniem drugim podejściem jest lepsza praktyka.

pa4080
źródło
6
Nie ma nic złego w korzystaniu ze ~skryptów. działa dokładnie tak samo, jak w wierszu poleceń. Problem polega na tym, że cytowanie blokuje ekspansję tyldy, jak wyjaśniono w odpowiedzi Zanny .
terdon
@terdon, zgadzam się. Ale nie powiedziałem, że coś jest nie tak, ale jest to lepszy pomysł, ponieważ należy zwracać mniejszą uwagę.
pa4080
5
Ale tutaj absolutnie nie ma różnicy między wierszem poleceń a skryptem. Fakt, że jest to w skrypcie, jest całkowicie nieistotny, miałbyś dokładnie ten sam błąd w wierszu poleceń. Problemem jest cytowanie, a nie to, że jest w skrypcie.
terdon
Chociaż jest to całkowicie prawdą, jest również słuszne, że używanie $HOMEw skryptach jest dobrym pomysłem.
deser
3
@ pa4080 Czy możesz dodać wyjaśnienie, dlaczego Twoim zdaniem lepiej jest rozwinąć $HOMEniż używać rozszerzenia tyldy? Jedynym wyjaśnieniem, które podałeś, jest powiedzenie: „to lepszy pomysł, ponieważ powinieneś mniej uważać”. Nie mam pojęcia co to znaczy. Czy możesz to wyjaśnić w edycji? Bez tego nic nie potwierdza twojej odpowiedzi, więc na pewno do niej należy. Tyldy został wymagane przez POSIX na jakiś czas teraz i linia hashbang skrypt jest #!/bin/bashtak przypuszczam przenośność nie jest powód.
Eliah Kagan
23

To nie działa, ponieważ ~jest cytowane. Cudzysłowy " tłumić tyldy ekspansji . Nie ma katalogu o dosłownej nazwie ~/bin. Jak wyjaśniono w man bash(moje podkreślenie):

Rozszerzenie Tilde

Jeśli słowo zaczyna się od nienotowanego znaku tyldy ( `~ '), wszystkie znaki poprzedzające pierwszy nienotowanych ukośnik (lub wszystkie znaki, gdy nie ma nienotowanych ukośnik) są uważane za przedrostkiem tyldy. Jeśli nie zacytowano żadnego ze znaków w prefiksie tyldy, 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. W przeciwnym razie przedrostek tyldy zostanie zastąpiony katalogiem domowym powiązanym z określoną nazwą logowania.

Możesz usunąć cudzysłowy , ponieważ ~jest to jedyny znak na ścieżce ~/bin, który spowoduje, że powłoka wykona rozwinięcie, a my chcemy rozwinięcia w tym przypadku. Powłoka nie będzie wykonywać żadnych dalszych rozszerzeń na skutek ekspansji tyldy, przynajmniej w Bash 4 , który wszystkie obecne lub zdalnie ostatnich wydaniach Ubuntu mają . Nawet jeśli katalog domowy zawiera nietypowe znaki, takie jak spacje, jest w porządku.

Albo można użyć $HOMEzamiast z ~, ponieważ ekspansja parametr nie jest tłumione przez cudzysłów, tylko przez pojedynczych cudzysłowach . Podwójne cudzysłowy nie zapewniają, że rozszerzona wartość nie jest sama w sobie przedmiotem dalszych rozwinięć, więc podział na słowa lub rozszerzenie nazwy pliku nie nastąpi. $HOMEDziała więc nawet z dziwnie nazwanymi katalogami domowymi, o ile zachowasz podwójne cudzysłowy.

Zanna
źródło
Zgodnie z tym stwierdzeniem „interpretacja parametrów nie jest tłumiona podwójnymi cudzysłowami, tylko pojedynczymi cudzysłowami” : wyjściem cd '~'jest -bash: cd: ~: No such file or directory.
pa4080
2
@ pa4080 Rozszerzenie ~nie jest częścią rozszerzenia parametru.
Barmar