Перерахуйте елементи з пробілами в zsh


10

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

files=(`ls`)
for f in $files; do
    print $f
done

Я, очевидно, не просто відтворюю ls, я просто хочу $fзахопити все ім’я файлу кожну ітерацію циклу.

Відповіді:


12

По-перше, я припускаю, що використання - lsце лише приклад. Ви не можете проаналізувати вихід lsбудь-якої оболонки, оскільки це неоднозначно. Прочитайте Чому ви не повинні розбирати вихід ls (1), якщо це для вас новина. У будь-якій оболонці для отримання списку файлів використовуйте символи, наприклад files=(*).

У zsh, як і в інших оболонках, результат заміни команд розбивається на слова на символи пробілу (точніше, за значенням IFS). (На відміну від інших оболонок, результат заміни команд не підлягає глобалізації в zsh.) Отже, якщо вихід lsкоманди є

hello world
wibble

потім files=($(ls))встановлює filesмасив містить 3 елементи: hello, worldі wibble.

Якщо підміна команд знаходиться в подвійних лапках, то розщеплення не проводиться. Ви можете виконати спеціальне розбиття за допомогою прапорців розширення параметрів . Використовуйте @прапор, щоб вказати, що результатом розщеплення має бути масив (як не дивно, вам потрібно зберегти розширення в подвійних лапках, тобто "${(@)…}", навіть якщо подвійний цитат буде розширюватися на кілька слів). Для розщеплення використовуйте sпрапор, наприклад, "${(@s:,:)…}"для розділення комами; fпрапор розщеплюється на тільки переклади рядків.

files=("${(@f)$(ls)}")

Зауважте, що правильний спосіб ітерації масиву взагалі полягає for f in $files[@]в тому, що $filesзнімає порожні елементи (тут це не має значення, оскільки елементи не будуть порожніми).

print $fінтерпретує $fяк перемикач, якщо він починається з а -і розширює зворотні риски в $f. Використовуйте print -r -- $fабо print -rn -- $fякщо ви не хочете додавати новий рядок після рядка.


Дякую. Так, ls був лише прикладом. На даний момент конкретної мети на увазі не було, я просто хочу знати, як цитувати або уникати елементів списку з будь-якої команди, яка може мати індивідуальні результати з пробілом у них.
Фелікс

Я вважаю заплутаним одне, чому зовнішнє () у ваших файлах = ("$ {(@ f) $ (ls)}") вираження необхідне для @f? І просто грати навколо (f), здається, працює добре, поки () з'являється зовні.
Koobz

@Koobz 1. Зовнішні (…)необхідні таким чином, що filesце масив, а не рядок (який містив би конкатенацію рядків з команди, скасовуючи розщеплення, виконане (f)). 2. З foo=$'one\n\nthree', contrast друком -rl $ {(f) foo} `і print "${(@f)foo}". Подвійні лапки потрібні для збереження порожніх рядків, з яких ви не отримаєте, lsале можуть статися з іншими командами.
Жиль "ТАК - перестань бути злим"

Цінується. Чи є якась рима чи причина цього безумства? Навіть там, що бентежить, чому зовнішній () просто знову не розділяє рядок на окремі слова, якщо проміжне значення - це моя об'єднана рядок. Наприклад, це схоже на строкову інтерполяцію в рубіні або php.
Koobz

@Koobz Причиною спеціального поводження з порожніми словами є історична сумісність із давно забутими старими версіями zsh. Причина автоматичного розщеплення полягає в тому, що це дивна і часто не бажана поведінка. Автоматичне розщеплення - це поведінка оболонки Борна, яка zsh не імітує, якщо ви цього не скажете.
Жил "ТАК - перестань бути злим"

2

У zsh ви можете використовувати розширення оболонки, яке не виконує розбиття слів за замовчуванням. Спробуйте

for f in /path/to/files/*; do
    print ${f}
done
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.