Как мне перебрать все строки, выводимые командой в zsh? - PullRequest
5 голосов
/ 13 октября 2011

Как перебрать все строки, выводимые командой с использованием zsh, без установки IFS?

Причина в том, что я хочу выполнить команду для каждого файла, выводимого командой, и некоторые из нихфайлы содержат пробелы.

Например, с учетом удаленного файла:

foo/bar baz/gamma

То есть один каталог 'foo', содержащий подкаталог 'bar baz', содержащий файл 'gamma'.

Затем запустится:

git ls-files --deleted | xargs ls

В этом файле будет сообщено, что он обрабатывается как два файла:' foo / bar 'и' /baz/gamma'.

Мне нужно, чтобы это обрабатывалось как один файл: 'foo / bar baz / gamma'.

Ответы [ 2 ]

7 голосов
/ 14 октября 2011

Если вы хотите выполнить команду один раз для всех строк:

ls "${(@f)$(git ls-files --deleted)}"

Флаг расширения параметра f означает разделение вывода команды на новые строки. Существует более общая форма (@s:||:) для разделения на произвольную строку, например ||. Флаг @ означает сохранение пустых записей. Несколько странно, что все раскрытие должно заключаться в двойные кавычки, чтобы избежать разбиения IFS на вывод подстановки команд , но оно будет выдавать отдельные слова для каждой записи.

Если вы хотите выполнить команду для каждой строки по очереди, переносимая идиома не особенно сложна:

git ls-filed --deleted | while IFS= read -r line; do ls $line; done

Если вы хотите выполнить команду столько раз, сколько позволяет ограничение длины командной строки, используйте zargs .

autoload -U zargs
zargs -- "${(@f)$(git ls-files --deleted)}" -- ls
4 голосов
/ 13 октября 2011

Использование tr и опция -0 xargs, при условии, что строки не содержат \000 (NUL), что является справедливым предположением, поскольку NUL является одним из символов, которые непоявляются в именах файлов:

git ls-files --deleted | tr '\n' '\000' | xargs -0 ls

, это превращает строку: foo/bar baz/gamma\n в foo/bar baz/gamma\000, которая xargs -0 знает, как обрабатывать

...