W moim środowisku Bash używam zmiennych zawierających spacje i używam tych zmiennych w ramach zastępowania poleceń. Niestety nie mogę znaleźć odpowiedzi na SE.
Jaki jest prawidłowy sposób cytowania moich zmiennych? Jak mam to zrobić, jeśli są zagnieżdżone?
DIRNAME=$(dirname "$FILE")
lub czy mam wycenę poza zamianą?
DIRNAME="$(dirname $FILE)"
lub obydwa?
DIRNAME="$(dirname "$FILE")"
lub czy używam tykania wstecznego?
DIRNAME=`dirname "$FILE"`
Jak to zrobić? Jak mogę łatwo sprawdzić, czy cytaty są ustawione poprawnie?
bash
shell
quoting
command-substitution
Kuzyn Kokaina
źródło
źródło
Odpowiedzi:
W kolejności od najgorszego do najlepszego:
DIRNAME="$(dirname $FILE)"
nie zrobi tego, co chcesz, jeśli$FILE
zawiera białe znaki lub znaki globowania\[?*
.DIRNAME=`dirname "$FILE"`
jest technicznie poprawny, ale backtyki nie są zalecane do rozszerzania poleceń ze względu na dodatkową złożoność podczas ich zagnieżdżania.DIRNAME=$(dirname "$FILE")
jest poprawne, ale tylko dlatego, że jest to zadanie . Jeśli użyjesz podstawienia polecenia w jakimkolwiek innym kontekście, takim jakexport DIRNAME=$(dirname "$FILE")
lubdu $(dirname "$FILE")
, brak cudzysłowów spowoduje problemy, jeśli wynik rozwinięcia zawiera białe znaki lub znaki globowania.DIRNAME="$(dirname "$FILE")"
jest zalecanym sposobem. Możesz zamienićDIRNAME=
na komendę i spację, nie zmieniając niczego innego, idirname
otrzymasz poprawny ciąg.Aby jeszcze bardziej poprawić:
DIRNAME="$(dirname -- "$FILE")"
działa, jeśli$FILE
zaczyna się od myślnika.DIRNAME="$(dirname -- "$FILE"; printf x)" && DIRNAME="${DIRNAME%?x}"
działa, nawet jeśli$FILE
kończy się na nowej linii, ponieważ$()
odcina nowe linie na końcu wyniku idirname
wypisuje nową linię po wyniku. Sheeshdirname
, dlaczego musisz być inny?Możesz zagnieżdżać rozszerzenia poleceń tak, jak chcesz. Z
$()
wami utworzyć nowy powołując kontekst, dzięki czemu można robić takie rzeczy:Zdajesz nie chcą spróbować z backticks.
źródło
$()
Zawsze tworzysz nowy kontekst cytowania”, więc to tak, jak poza zewnętrznymi cytatami. O ile mi wiadomo, nie ma w tym nic więcej.Zawsze możesz pokazać efekty cytowania zmiennych za pomocą
printf
.Podział słów na
var1
:var1
cytowany, więc bez podziału słów:Podział słów w
var1
środku$()
, co odpowiadaecho "hello" "world"
:Bez podziału słów
var1
, nie ma problemu z nie cytowaniem$()
:var1
Ponowne dzielenie słów :Cytując oba, najłatwiejszy sposób, aby się upewnić.
Problem globbingowy
Brak cytowania zmiennej może również prowadzić do globalnego rozszerzenia jej zawartości:
Zauważ, że dzieje się to po rozwinięciu zmiennej. Podczas przypisywania nie jest konieczne cytowanie globu:
Użyj,
set -f
aby wyłączyć to zachowanie:I
set +f
ponownie włączyć go:źródło
var1='hello * world'
aby zilustrować problem globowania.Dodatek do zaakceptowanej odpowiedzi:
Chociaż ogólnie zgadzam się z odpowiedzią @ l0b0 tutaj, podejrzewam, że umieszczenie odsłoniętych backticksów na liście „najgorszych do najlepszych” przynajmniej częściowo wynika z założenia, które
$(...)
jest dostępne wszędzie. Zdaję sobie sprawę, że pytanie określa Bash, ale zdarza się, że Bash ma na myśli wiele/bin/sh
, co nie zawsze może być pełną powłoką Bourne Again.W szczególności zwykła powłoka Bourne'a nie będzie wiedziała, co z tym zrobić
$(...)
, więc skrypty, które twierdzą, że są z nią kompatybilne (np. Poprzez#!/bin/sh
linię shebang) prawdopodobnie źle się zachowają, jeśli faktycznie są uruchamiane przez „prawdziwe”/bin/sh
- to jest szczególnie interesujące, gdy powiedzmy, tworzenie skryptów inicjujących lub pakowanie skryptów wstępnych i końcowych, i może wylądować w zaskakującym miejscu podczas instalacji systemu podstawowego.Jeśli coś takiego brzmi jak coś, co planujesz zrobić z tą zmienną, zagnieżdżanie jest prawdopodobnie mniejszym problemem niż faktyczne, przewidywalne uruchomienie skryptu. Gdy jest to wystarczająco prosta sprawa, a przenośność stanowi problem, nawet jeśli spodziewam się, że skrypt będzie zwykle działał w systemach, w których
/bin/sh
znajduje się Bash, często z tego powodu używam back -icksa z wieloma przypisaniami zamiast zagnieżdżania.Powiedziawszy to wszystko, wszechobecność powłok, które implementują
$(...)
(Bash, Dash i in.), Pozostawia nas w dobrym miejscu, aby trzymać się ładniejszej, łatwiejszej do zagnieżdżenia, a ostatnio w większości przypadków preferowanej składni POSIX, dla wszystkie powody wymienione w l0b0.Poza tym: czasami pojawia się to również na StackOverflow -
źródło