Що таке розділення слів? Чому це важливо в програмуванні оболонок?


16

Я плутаюсь у ролі розбиття розбиття слова zsh. Я не піддавався цій концепції під час програмування на C, Python або MATLAB, і це викликало мій інтерес, чому розщеплення слів здається чимось специфічним для програмування оболонок.

Я раніше читав про розділення слів на цьому та інших сайтах, але не знайшов чіткого пояснення цієї концепції. У Вікіпедії є визначення розділення слів, але, схоже, немає посилань на те, як воно застосовується до оболонок Unix.

Ось приклад моєї плутанини в zsh:

У поширених питаннях про Z Shell я прочитав наступне:

3.1: Чому $varтам, де var="foo bar"не робити того, чого я очікую?

У більшості похідних оболонки Борна багато змінні змінні, такі як var="foo bar" розділяються на слова, коли передаються команді або використовуються в for foo in $varциклі. За замовчуванням zsh не має такої поведінки: змінна залишається недоторканою. (Це не помилка! Дивіться нижче.) SH_WORD_SPLITІснує можливість забезпечити сумісність.

Однак у посібнику Z Shell я прочитав таке:

SH_WORD_SPLIT (-y) <K> <S>

Причиняє розщеплення поля для розширень без котируваних параметрів. Зауважте, що ця опція не має нічого спільного з розділенням слів. (Див. Розширення параметрів.)

Чому йдеться про те, що неSH_WORD_SPLIT має нічого спільного з розділенням слів? Чи не розбиття слів саме для чого це?

Відповіді:


22

Ранні оболонки мали лише один тип даних: рядки. Але звичайно маніпулювати списками рядків, як правило, при передачі декількох імен файлів як аргументів програмі. Інший поширений випадок використання для розщеплення - це коли команда виводить список результатів: висновок команди - це рядок, але потрібні дані - це список рядків. Щоб зберегти список імен файлів у змінній, слід розмістити пробіли між ними. Потім такий сценарій оболонки

files="foo bar qux"
myprogram $files

викликається myprogramтрьома аргументами, як оболонка розділяє рядок $filesна слова. У той час пробіли в іменах файлів були заборонені або широко вважалися не виконаними.

Korn оболонки введені масиви: ви можете зберігати список рядків у змінній. Оболонка Корна залишалася сумісною з створеною тоді оболонкою Борна, тому голі розширення змінних, що постійно зазнавали розщеплення слів, і використання масивів вимагало деяких синтаксичних накладних витрат. Ви б написали фрагмент вище

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

Zsh мав масиви з самого початку, і його автор вибрав дизайн більш безпечної мови за рахунок зворотної сумісності. У zsh (за правилами розширення за замовчуванням) $varне відбувається певного розділення слів; якщо ви хочете зберегти список слів у змінній, вам призначено використовувати масив; і якщо ви дійсно хочете розділити слова, можете написати $=var.

files=(foo bar qux)
myprogram $files

У цей час пробіли в іменах файлів - це те, з чим потрібно впоратися, тому що багато користувачів очікують, що вони працюватимуть, і тому, що багато сценаріїв виконуються в контекстах, залежних від безпеки, де зловмисник може контролювати імена файлів. Тож автоматичне розщеплення слів часто є неприємністю; отже, моя загальна порада завжди використовувати подвійні лапки, тобто писати "$foo", якщо ви не розумієте, для чого вам потрібно розділити слова в конкретному випадку використання. (Зауважте, що голі змінні розширення також зазнають глобалізації.)


Дякую Жиллю, це справді корисно! Чи правильно сказати, що грубо кажучи розбиття слів перетворює рядки форми "word1 word2 word3"в списки / масиви форми "word1" "word2" "word3"? Я також оновив ОП із конкретним джерелом плутанини в zsh.
Амеліо Васкес-Рейна

1
@intrpc "Розбиття слів" - це не розщеплення на слова природної мови, а на $IFSсимволи. Звідси «розщеплення поля» - краща назва. Але "розщеплення слів" часто використовується для цього поняття в оболонці літератури. Документація zsh хитається на словах.
Жил "ТАК - перестань бути злим"

1
Дивіться також rc(оболонка plan9, також перенесена в Unix) для ще кращого дизайну, ніж zsh, коли мова йде про змінні та масиви.
Стефан Шазелас

3

Розщеплення слів насправді не є специфічною оболонкою.

Більшість програм, яким потрібно проаналізувати введення тексту, використовують перший вид розбиття слів як перший крок. Це робиться перед тим, як ідентифікувати з цих "слів", цифр, операторів, рядків, лексем та будь-яких подібних об'єктів, які їм потрібно обробити.

Що стосується оболонок, це те, що вони повинні правильно скласти список аргументів команд, що називаються (C argc / argv, python sys.argv), включаючи передачу аргументів із вбудованими пробілами, порожні аргументи, спеціальні роздільники тощо. Багато оболонок використовують змінну IFS, щоб забезпечити там деяку гнучкість.


3

У цьому конкретному випадку Zsh розбиття слів визначається дещо інакше, ніж розділення поля.

Поміркуйте prog a b c, він подасть три аргументи незалежно від того, як ви їх встановили IFS. Це розщеплення слів .

Якщо ви зробите A="a b c"; prog $Aце, він передасть три аргументи, якщо IFSвключає пробіл або один аргумент інакше. Це поділ поля .

Визначення тут тонкі. Документ Zsh намагається сказати - це, навіть якщо ви вимкнете цю опцію, prog a b cвсе одно отримаєте окремі аргументи (на що люди завжди очікують).


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.