выполнить команду один раз в строке ввода?

<p>я хочу выполнить команду java один раз для каждого совпадения <code>ls | grep pattern -</code>. в этом случае, я думаю, я мог бы сделать <code>find pattern -exec java myprog '{}' \;</code> но меня интересует общий случай - есть ли простой способ сказать "выполнить команду один раз для каждой строки стандартного ввода"? (в рыбе или баш.)</p>

<p>вот что делает <code>xargs</code>.</p><pre><code>... | xargs command </code></pre>

<p> <a href="https://unix.stackexchange.com/a/7560">принятый ответ</a> имеет правильную идею, но ключ должен передать <code>xargs</code> the <code>-n1</code> switch, что означает "выполнить команду один раз для каждой строки вывода:"</p><pre><code>cat file... | xargs -n1 command </code></pre><p>или для одного входного файла вы можете полностью исключить канал из <code>cat</code> и просто использовать:</p><pre><code><file xargs -n1 command </code></pre>

<p>в bash или любой другой оболочке в стиле bourne (ash, ksh, zsh,…):</p><pre><code>while read -r line; do command "$line"; done read -r читает одну строку из стандартного ввода (read без -r интерпретирует обратную косую черту, вы этого не хотите). таким образом, вы можете сделать одно из следующего:$ command | while read -r line; do command "$line"; done $ while read -r line; do command "$line"; done <file 

я согласен с китом, xargs - самый общий инструмент для работы.я обычно использую трехэтапный подход. делать базовые вещи, пока у вас не будет то, что вы хотели бы работать подготовьте строку с помощью awk, чтобы он получил правильный синтаксис тогда пусть xargs выполнит его, может быть, с помощью bash. есть меньшие и более быстрые способы, но эти способы почти всегда работают.простой пример:ls | grep xls | awk '{print "myjavaprog --arg1 42 --arg2 "$1"\0"}' | xargs -0 bash -c </code></pre><p>2 первые строки выбирают несколько файлов для работы, затем awk подготавливает строку nice с командой для выполнения и некоторыми аргументами, а $ 1 - это первый вход столбца из канала. и, наконец, я убедился, что xargs отправляет эту строку в bash, которая просто выполняет ее.это немного излишне, но этот рецепт помог мне во многих местах, так как он очень гибкий.

gnu parallel сделан для такого рода задач. самое простое использование:cat stuff | grep pattern | parallel java myprog посмотрите вступительное видео, чтобы узнать больше: <a href="http://www.youtube.com/watch?v=opaigyxksuq">http://www.youtube.com/watch?v=opaigyxksuq 

также, while read цикл в рыбной оболочке (я предполагаю, что вы хотите рыбную оболочку, учитывая, что вы использовали <a href="/questions/tagged/fish">fish тег).command | while read line command $line end </code></pre><p>несколько замечаний.</p><ul> <li><code>read</code> не берет <code>-r</code>, и он не интерпретирует обратную косую черту, чтобы облегчить наиболее распространенный вариант использования.</li> <li>вам не нужно цитировать <code>$line, в отличие от bash, fish не разделяет переменные по пробелам. command само по себе является синтаксической ошибкой (чтобы отловить такое использование аргументов-заполнителей). замените его настоящей командой. 

имея дело с потенциально неанизированными входами, я хотел бы видеть всю работу, "прописанную", построчно для визуального осмотра, прежде чем запускать ее (особенно когда это что-то разрушительное, например, очистка почтовых ящиков людей).поэтому я создаю список параметров (т. е. имена пользователей), передаю его в файл по одной записи на строку, например:johndoe jamessmith janebrown затем я открываю список в vim и искажаю его с помощью выражений поиска и замены, пока не получу список полных команд, которые нужно выполнить, например:/bin/rm -fr /home/johndoe /bin/rm -fr /home/jamessmith таким образом, если ваше регулярное выражение неполное, вы увидите, в какой команде будут потенциальные проблемы (т. е. /bin/rm -fr johnnyo connor). таким образом, вы можете отменить свое регулярное выражение и попробовать его снова с более надежной версией. известно, что искажение имен известно, потому что трудно позаботиться о всех случаях эджа, таких как ван гог, о'коннорс, сент-клер, смит-вессон.имея set hlsearch полезно для этого в vim, так как в нем будут выделены все совпадения, чтобы вы могли легко определить, не совпадает ли он или совпадает непреднамеренным образом.после того, как ваше регулярное выражение станет идеальным, и оно поймает все случаи, для которых вы можете проверить/подумать, я обычно преобразую его в выражение sed, чтобы его можно было полностью автоматизировать для следующего запуска.в тех случаях, когда количество строк ввода не позволяет выполнить визуальный осмотр, я настоятельно рекомендую выводить команду на экран (или, что еще лучше, в журнал) перед ее выполнением, поэтому, если она выдает ошибку, вы точно знаете, какая команда вызвала это потерпеть неудачу. затем вы можете вернуться к исходному регулярному выражению и настроить еще раз.

здесь копировальную пасту вы можете сразу использовать:cat list.txt | xargs -i{} command parameter {} parameter элемент из списка будет помещен туда, где {}, а остальные команды и параметры будут использоваться как есть.

это возможно с xargs, как указано в других ответах. мы должны различать две особенности в части вопроса "один раз на строку": один раз: используйте -n 1, это гарантирует, что команда вызывается ровно один раз для каждого аргумента. однако по умолчанию xargs предполагает, что аргументы разделены пробелами - это приведет к разрыву, когда файлы будут содержать пробелы. в строке: используйте -d 'n' или предварительно обработайте ввод с помощью tr 'n' '0' и используйте -0. это делает команду устойчивой к пробелам на входе. окончательная командная строка становится:.... | xargs -n 1 -d 'n' <command> или (с tr).... | tr 'n' '0' | xargs -n 1 -0 <command> если ваша команда может обрабатывать несколько аргументов одновременно (например, grep или sed), вы можете опустить -n 1 для ускорения работы во многих случаях.

если программа игнорирует канал, но принимает файлы в качестве аргументов, тогда вы можете просто указать его на специальный файл /dev/stdin.я не знаком с java, но вот пример того, как вы бы это сделали для bash:$ echo $'pwd n cd / n pwd' |bash /dev/stdin /home/rolf / $ необходим bash для перевода <code>\n</code> в новые строки. я не уверен почему.</p>

<p>я предпочитаю это - разрешить многострочные команды и очистить код</p><pre><code>find -type f -name filenam-pattern* | while read -r f do echo $f cat $f | grep 'some text' done </code></pre><p>ref <a href="https://stackoverflow.com/a/3891678/248616">https://stackoverflow.com/a/3891678/248616</a> </p>