Мне кажется, что все существующие ответы на этой странице неверны, включая ответ, помеченный как правильный. Это связано с тем, что вопрос сформулирован неоднозначно.
Сводка: Если вы хотите выполнить команду "ровно один раз для каждой заданной строки ввода", передав всю строку (без новой строки) команде как один аргумент, , тогда это лучший UNIX-совместимый способ сделать это:
... | tr '\n' '\0' | xargs -0 -n1 ...
GNU xargs
может иметь или не иметь полезных расширений, которые позволяют вам отказаться от tr
, но они недоступны в OS X и других системах UNIX.
Теперь для длинного объяснения ...
При использовании xargs необходимо учитывать две проблемы:
- как он разбивает входные данные на «аргументы»; и
- сколько аргументов для передачи дочерней команды за один раз.
Чтобы протестировать поведение xargs, нам нужна утилита, которая показывает, сколько раз она выполняется и сколько аргументов. Я не знаю, есть ли стандартная утилита для этого, но мы можем довольно легко ее кодировать в bash:
#!/bin/bash
echo -n "-> "; for a in "$@"; do echo -n "\"$a\" "; done; echo
Предполагая, что вы сохраните его как show
в своем текущем каталоге и сделаете его исполняемым, вот как это работает:
$ ./show one two 'three and four'
-> "one" "two" "three and four"
Теперь, если исходный вопрос действительно касается пункта 2. выше (как мне кажется, после прочтения его несколько раз), и его следует читать так (изменения жирным шрифтом):
Как я могу заставить xargs выполнять команду ровно один раз для каждого аргумента введенного ввода? Поведение по умолчанию состоит в том, что входные данные разделяются на аргументы и выполняются команды как можно меньшее число раз , передавая несколько аргументов каждому экземпляру.
тогда ответ -n 1
.
Давайте сравним поведение xargs по умолчанию, которое разделяет вводные данные вокруг пробела и вызывает команду как можно меньше раз:
$ echo one two 'three and four' | xargs ./show
-> "one" "two" "three" "and" "four"
и его поведение с -n 1
:
$ echo one two 'three and four' | xargs -n 1 ./show
-> "one"
-> "two"
-> "three"
-> "and"
-> "four"
Если, с другой стороны, первоначальный вопрос касался пункта 1. Разделение входных данных и его нужно было читать следующим образом (многие люди, приходящие сюда, похоже, считают, что это так, или путают две проблемы):
Как я могу заставить xargs выполнить команду с точно одним аргументом для каждой заданной строки ввода? Его поведение по умолчанию состоит в разбиении строк вокруг пробела .
тогда ответ более тонкий.
Можно подумать, что -L 1
может помочь, но оказывается, что это не меняет синтаксический анализ аргументов. Он выполняет команду только один раз для каждой строки ввода с таким количеством аргументов, сколько было в этой строке ввода:
$ echo $'one\ntwo\nthree and four' | xargs -L 1 ./show
-> "one"
-> "two"
-> "three" "and" "four"
Мало того, но если строка заканчивается пробелом, она добавляется к следующему:
$ echo $'one \ntwo\nthree and four' | xargs -L 1 ./show
-> "one" "two"
-> "three" "and" "four"
Очевидно, что -L
не имеет отношения к изменению способа, которым xargs разделяет входные данные на аргументы.
Единственный аргумент, который делает это кроссплатформенным способом (исключая расширения GNU), это -0
, который разбивает входные данные вокруг байтов NUL.
Тогда нужно просто переводить строки в NUL с помощью tr
:
$ echo $'one \ntwo\nthree and four' | tr '\n' '\0' | xargs -0 ./show
-> "one " "two" "three and four"
Теперь синтаксический анализ аргументов выглядит хорошо, включая завершающий пробел.
Наконец, если вы объедините эту технику с -n 1
, вы получите ровно одно выполнение команды на строку ввода, независимо от того, какой у вас ввод, что может быть еще одним способом взглянуть на исходный вопрос (возможно, наиболее интуитивно понятный, учитывая название):
$ echo $'one \ntwo\nthree and four' | tr '\n' '\0' | xargs -0 -n1 ./show
-> "one "
-> "two"
-> "three and four"