Co to jest dzielenie słów? Dlaczego jest to ważne w programowaniu powłoki?

16

Mylę się co do roli, jaką odgrywa podział słów zsh. Nie byłem narażony na tę koncepcję podczas programowania w C, Python lub MATLAB, co spowodowało moje zainteresowanie tym, dlaczego dzielenie słów wydaje się być czymś specyficznym dla programowania powłoki.

Czytałem wcześniej o dzieleniu słów na tej i innych stronach, ale nie znalazłem jasnego wyjaśnienia tego pojęcia. Wikipedia ma definicję podziału słów, ale wydaje się, że nie ma odniesień do tego, jak ma ona zastosowanie do powłok uniksowych.

Oto przykład mojego zamieszania w zsh:

W FAQ Z Shell przeczytałem:

3.1: Dlaczego $vargdzie var="foo bar"nie robić to, co się spodziewać?

W większości pochodnych powłoki Bourne'a zmienne o wielu słowach, takie jak var="foo bar" dzielone na słowa po przekazaniu do polecenia lub w for foo in $varpętli. Domyślnie zsh nie ma takiego zachowania: zmienna pozostaje nienaruszona. (To nie jest błąd! Zobacz poniżej.) SH_WORD_SPLITIstnieje opcja zapewniająca zgodność.

Jednak w podręczniku Z Shell przeczytałem:

SH_WORD_SPLIT (-y) <K> <S>

Powoduje, że podział na pola jest wykonywany dla niecytowanych rozszerzeń parametrów. Pamiętaj, że ta opcja nie ma nic wspólnego z dzieleniem słów. (Zobacz Rozszerzanie parametrów.)

Dlaczego mówi, że nieSH_WORD_SPLIT ma to nic wspólnego z dzieleniem słów? Czy słowo nie dzieli dokładnie tego, o co w tym wszystkim chodzi?

Amelio Vazquez-Reina
źródło

Odpowiedzi:

22

Wczesne powłoki miały tylko jeden typ danych: łańcuchy. Ale często manipuluje się listami ciągów, zwykle przy przekazywaniu wielu nazw plików jako argumentów do programu. Innym częstym przypadkiem użycia podziału jest sytuacja, gdy polecenie wyświetla listę wyników: wynikiem polecenia jest ciąg, ale pożądane dane to lista ciągów. Aby przechowywać listę nazw plików w zmiennej, należy wstawiać spacje między nimi. Potem taki skrypt powłoki

files="foo bar qux"
myprogram $files

wywołany myprogramtrzema argumentami, gdy powłoka podzieliła ciąg $filesna słowa. W tym czasie spacje w nazwach plików były albo zabronione, albo powszechnie uważane za nie zrobione.

Korn shell wprowadzono tablice: można przechowywać listę ciągów w zmiennej. Powłoka Korna pozostała kompatybilna z ustanowioną wówczas powłoką Bourne'a, więc nagie zmienne rozszerzenia podlegały podziałowi słów, a używanie tablic wymagało pewnego nakładu syntaktycznego. Napisz fragment kodu powyżej

files=(foo bar qux)
myprogram "${files[@]}"

Zsh miał tablice od samego początku, a jego autor opowiedział się za rozsądniejszym projektem języka kosztem wstecznej kompatybilności. W zsh (zgodnie z domyślnymi regułami rozwijania) $varnie wykonuje podziału słów; jeśli chcesz przechowywać listę słów w zmiennej, to powinieneś użyć tablicy; a jeśli naprawdę chcesz dzielić słowa, możesz pisać $=var.

files=(foo bar qux)
myprogram $files

Obecnie spacje w nazwach plików są czymś, z czym trzeba sobie poradzić, zarówno dlatego, że wielu użytkowników oczekuje, że będą działać, jak i dlatego, że wiele skryptów jest wykonywanych w kontekstach wrażliwych dla bezpieczeństwa, w których atakujący może kontrolować nazwy plików. Automatyczne dzielenie słów jest często uciążliwe; stąd moja ogólna rada, aby zawsze używać podwójnych cudzysłowów, tj. pisać "$foo", chyba że rozumiesz, dlaczego potrzebujesz podziału słów w konkretnym przypadku użycia. (Uwaga: rozszerzenia globalne zmiennych również podlegają globowaniu).

Gilles „SO- przestań być zły”
źródło
Dzięki Gilles, to jest naprawdę pomocne! Czy słusznie jest powiedzieć, że z grubsza mówiąc dzielenie wyrazów przekształca ciągi formularza "word1 word2 word3"w listy / tablice formularza "word1" "word2" "word3"? Zaktualizowałem również OP o konkretne źródło zamieszania w Zsh.
Amelio Vazquez-Reina,
1
@intrpc „Podział słów” nie dzieli się na słowa w języku naturalnym, ale na $IFSznaki. Dlatego „podział pola” jest lepszą nazwą. Ale „dzielenie słów” jest często używane w tej koncepcji w literaturze powłoki. Dokumentacja Zsh spiera się o słowa.
Gilles: „Przestańcie być źli”,
1
Zobacz także rc(powłoka plan9, również przeniesiona do Uniksa), aby uzyskać jeszcze lepszy projekt niż zsh, jeśli chodzi o zmienne i tablice.
Stéphane Chazelas
3

Podział słów nie jest tak naprawdę specyficzny dla powłoki.

Większość programów, które muszą analizować wprowadzanie tekstu, używa pewnego rodzaju podziału słów jako pierwszego kroku. Odbywa się to przed identyfikacją na podstawie tych „słów”, liczb, operatorów, ciągów, tokenów i wszelkich podobnych podmiotów, które muszą przetworzyć.

Specyficzne dla powłok jest to, że muszą poprawnie zbudować listę argumentów poleceń o nazwie (C argc / argv, python sys.argv), w tym przekazywanie argumentów z osadzonymi spacjami, pustymi argumentami, niestandardowymi ogranicznikami i tak dalej. Wiele powłok używa zmiennej IFS, aby zapewnić tam pewną elastyczność.

jlliagre
źródło
3

W tym konkretnym przypadku Zsh podział słowa jest definiowany nieco inaczej niż podział pola.

Zastanów się prog a b c, przekaże trzy argumenty, bez względu na to, jak ustawisz IFS. To jest dzielenie słów .

Jeśli to zrobisz A="a b c"; prog $A, przekaże trzy argumenty, jeśli IFSzawiera spację lub jeden argument inaczej. To jest dzielenie pól .

Definicje tutaj są subtelne. Dokument Zsh próbuje powiedzieć, że nawet jeśli wyłączysz tę opcję, prog a b cnadal otrzymają osobne argumenty (czego ludzie zawsze oczekują).

Hot.PxL
źródło
1
Bart Schaefer, wieloletni programista zsh, potwierdza, że ​​rzeczywiście jest to zamierzone znaczenie tego tekstu .
Stéphane Chazelas,