Rozwinięcie ciągu cytowanego a niecytowanego


11
  1. for i in $(xrandr); do echo "$i" ; done
  2. for i in "$(xrandr)"; do echo "$i"; done
  3. for i in "$(xrandr)"; do echo $i; done

Rozumiem, dlaczego 1 różni się od 2. Ale dlaczego 3 daje inny wynik niż 2? Proszę wyjaśnić również wynik. Jak cytaty działają na nowych liniach?



Odpowiedzi:


19

Niecytowana zmienna (jak w $var) lub podstawienie polecenia (jak w $(cmd)lub `cmd`) to operator split + glob w powłokach podobnych do Bourne'a.

Oznacza to, że ich zawartość jest podzielona zgodnie z bieżącą wartością $IFSzmiennej specjalnej (która domyślnie zawiera znaki spacji, tabulacji i nowego wiersza)

A następnie każde słowo powstałe w wyniku tego podziału podlega generowaniu nazw plików (zwanych także globowaniem lub rozszerzaniem nazw plików ), to znaczy są one uważane za wzorce i są rozwijane do listy plików pasujących do tego wzorca.

W związku z for i in $(xrandr)tym $(xrandr), ponieważ nie ma go w cudzysłowie, jest podzielony na ciągi znaków spacji, tabulacji i nowego wiersza. Każde słowo powstałe w wyniku tego podziału jest sprawdzane pod kątem pasujących nazw plików (lub pozostawione tak, jakby nie pasowały do ​​żadnego pliku) i forzapętla je wszystkie.

W for i in "$(xrandr)"nie używamy operatora split + glob, ponieważ cytowane jest podstawienie polecenia , więc w pętli jest jedno przejście na jedną wartość: wynik xrandr(bez końcowych znaków nowego wiersza, które pasują do zastępowania poleceń ).

Jednak w echo $i, $inie jest ponownie cytowany, więc ponownie treść $ijest podzielona i podlega generowaniu nazw plików, a te są przekazywane jako osobne argumenty do echopolecenia (i echowyprowadzają jego argumenty oddzielone spacjami).

Lekcja nauczyła się:

  • jeśli nie chcesz dzielenia słów ani generowania nazw plików , zawsze podawaj rozszerzenia zmiennych i podstawienia poleceń
  • jeśli chcesz podzielić słowa lub generować nazwy plików , pozostaw je bez cudzysłowu, ale $IFSodpowiednio je ustaw i / lub włącz lub wyłącz generowanie nazw plików w razie potrzeby ( set -f, set +f).

Zazwyczaj w powyższym przykładzie, jeśli chcesz zapętlić pustą, oddzieloną listę słów na wyjściu xrandr, musisz:

  • pozostaw $IFSwartość domyślną (lub usuń ją), aby podzielić na puste
  • Zastosowanie set -fdo wyłączenia generowania nazw plików, chyba że jesteś pewien, że xrandrnigdy nie wyprowadza dowolny *lub ?lub [znaków (które są symbole wieloznaczne stosowane we wzorcach generacji filename)

A następnie używaj tylko operatora split + glob (pozostaw tylko zastępowanie poleceń lub rozwijanie zmiennych bez cudzysłowu) w inczęści forpętli:

set -f; unset -v IFS
for i in $(xrandr); do whatever with "$i"; done

Jeśli chcesz zapętlić (niepuste) linie danych xrandrwyjściowych, musisz ustawić $IFSznak nowej linii:

IFS='
'

4

Cytowana nowa linia to nowa linia. echo "$1"Daje więc echo pojedynczego argumentu wiersza poleceń, który następnie drukuje nowe wiersze bezpośrednio.

Niecytowana nowa linia to biała spacja. echo $1Daje więc echo wielu argumentów wiersza poleceń, które wypisują je jeden po drugim oddzielone spacjami.


Nie cytowana nowa linia to spacja, to trochę za dużo skrótu, aby być naprawdę użytecznym jako wyjaśnienie zachowania tutaj IMO.
Stéphane Chazelas,
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.