Заставьте xargs выполнять команду один раз для каждой строки ввода
-
11-07-2019 - |
Вопрос
Как я могу заставить xargs выполнять команду ровно один раз для каждой введенной строки?Поведение по умолчанию заключается в разделении строк на части и выполнении команды один раз, передавая несколько строк в каждый экземпляр.
От http://en.wikipedia.org/wiki/Xargs:
поиск /путь -введите f -print0 | xargs -0 rm
В этом примере find передает входные данные xargs с длинным списком имен файлов.затем xargs разбивает этот список на подсписки и вызывает rm один раз для каждого подсписка.Это более эффективно, чем эта функционально эквивалентная версия:
найти /ввести путь f -exec rm '{}' \;
Я знаю, что find имеет флаг "exec".Я просто цитирую наглядный пример из другого ресурса.
Решение
Следующее будет работать только в том случае, если у вас нет пробелов во входных данных:
xargs -L 1
xargs --max-lines=1 # synonym for the -L option
со справочной страницы:
-L max-lines
Use at most max-lines nonblank input lines per command line.
Trailing blanks cause an input line to be logically continued on
the next input line. Implies -x.
Другие советы
Мне кажется, что все существующие ответы на этой странице неверны, включая ответ, помеченный как правильный. Это связано с тем, что вопрос сформулирован неоднозначно.
Резюме . & nbsp; Если вы хотите выполнить команду " ровно один раз для каждой указанной строки ввода, " передав всю команду (без новой строки) в качестве одиночного аргумента, тогда это лучший 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
Мало того, но если строка заканчивается пробелом, она добавляется к следующему:
$ echo
Очевидно, что -L
не касается изменения способа, которым xargs разделяет входные данные на аргументы.
Единственный аргумент, который делает это кроссплатформенным способом (исключая расширения GNU), это -0
, который разбивает входные данные вокруг байтов NUL.
Тогда нужно просто переводить строки в NUL с помощью tr
:
$ echo
Теперь разбор аргументов выглядит хорошо, включая завершающий пробел.
Наконец, если вы объедините эту технику с -n 1
, вы получите ровно одно выполнение команды на каждую строку ввода, независимо от того, какой у вас ввод, что может быть еще одним способом взглянуть на исходный вопрос ( возможно, наиболее интуитивный, учитывая название):
$ echo one\ntwo\nthree and four' | xargs -L 1 ./show
-> "one"
-> "two"
-> "three" "and" "four"
Мало того, но если строка заканчивается пробелом, она добавляется к следующему:
<*>
Очевидно, что -L
не касается изменения способа, которым xargs разделяет входные данные на аргументы.
Единственный аргумент, который делает это кроссплатформенным способом (исключая расширения GNU), это -0
, который разбивает входные данные вокруг байтов NUL.
Тогда нужно просто переводить строки в NUL с помощью tr
:
<*>
Теперь разбор аргументов выглядит хорошо, включая завершающий пробел.
Наконец, если вы объедините эту технику с -n 1
, вы получите ровно одно выполнение команды на каждую строку ввода, независимо от того, какой у вас ввод, что может быть еще одним способом взглянуть на исходный вопрос ( возможно, наиболее интуитивный, учитывая название):
<*>one \ntwo\nthree and four' | xargs -L 1 ./show
-> "one" "two"
-> "three" "and" "four"
Очевидно, что -L
не касается изменения способа, которым xargs разделяет входные данные на аргументы.
Единственный аргумент, который делает это кроссплатформенным способом (исключая расширения GNU), это -0
, который разбивает входные данные вокруг байтов NUL.
Тогда нужно просто переводить строки в NUL с помощью tr
:
<*>
Теперь разбор аргументов выглядит хорошо, включая завершающий пробел.
Наконец, если вы объедините эту технику с -n 1
, вы получите ровно одно выполнение команды на каждую строку ввода, независимо от того, какой у вас ввод, что может быть еще одним способом взглянуть на исходный вопрос ( возможно, наиболее интуитивный, учитывая название):
<*>one\ntwo\nthree and four' | xargs -L 1 ./show
-> "one"
-> "two"
-> "three" "and" "four"
Мало того, но если строка заканчивается пробелом, она добавляется к следующему:
<*>
Очевидно, что -L
не касается изменения способа, которым xargs разделяет входные данные на аргументы.
Единственный аргумент, который делает это кроссплатформенным способом (исключая расширения GNU), это -0
, который разбивает входные данные вокруг байтов NUL.
Тогда нужно просто переводить строки в NUL с помощью tr
:
<*>
Теперь разбор аргументов выглядит хорошо, включая завершающий пробел.
Наконец, если вы объедините эту технику с -n 1
, вы получите ровно одно выполнение команды на каждую строку ввода, независимо от того, какой у вас ввод, что может быть еще одним способом взглянуть на исходный вопрос ( возможно, наиболее интуитивный, учитывая название):
<*>one \ntwo\nthree and four' | tr '\n' '\0' | xargs -0 ./show
-> "one " "two" "three and four"
Теперь разбор аргументов выглядит хорошо, включая завершающий пробел.
Наконец, если вы объедините эту технику с -n 1
, вы получите ровно одно выполнение команды на каждую строку ввода, независимо от того, какой у вас ввод, что может быть еще одним способом взглянуть на исходный вопрос ( возможно, наиболее интуитивный, учитывая название):
Мало того, но если строка заканчивается пробелом, она добавляется к следующему:
<*> Очевидно, что -L
не касается изменения способа, которым xargs разделяет входные данные на аргументы.
Единственный аргумент, который делает это кроссплатформенным способом (исключая расширения GNU), это -0
, который разбивает входные данные вокруг байтов NUL.
Тогда нужно просто переводить строки в NUL с помощью tr
:
Теперь разбор аргументов выглядит хорошо, включая завершающий пробел.
Наконец, если вы объедините эту технику с -n 1
, вы получите ровно одно выполнение команды на каждую строку ввода, независимо от того, какой у вас ввод, что может быть еще одним способом взглянуть на исходный вопрос ( возможно, наиболее интуитивный, учитывая название):
Очевидно, что -L
не касается изменения способа, которым xargs разделяет входные данные на аргументы.
Единственный аргумент, который делает это кроссплатформенным способом (исключая расширения GNU), это -0
, который разбивает входные данные вокруг байтов NUL.
Тогда нужно просто переводить строки в NUL с помощью tr
:
Теперь разбор аргументов выглядит хорошо, включая завершающий пробел.
Наконец, если вы объедините эту технику с -n 1
, вы получите ровно одно выполнение команды на каждую строку ввода, независимо от того, какой у вас ввод, что может быть еще одним способом взглянуть на исходный вопрос ( возможно, наиболее интуитивный, учитывая название):
Мало того, но если строка заканчивается пробелом, она добавляется к следующему:
<*> Очевидно, что -L
не касается изменения способа, которым xargs разделяет входные данные на аргументы.
Единственный аргумент, который делает это кроссплатформенным способом (исключая расширения GNU), это -0
, который разбивает входные данные вокруг байтов NUL.
Тогда нужно просто переводить строки в NUL с помощью tr
:
Теперь разбор аргументов выглядит хорошо, включая завершающий пробел.
Наконец, если вы объедините эту технику с -n 1
, вы получите ровно одно выполнение команды на каждую строку ввода, независимо от того, какой у вас ввод, что может быть еще одним способом взглянуть на исходный вопрос ( возможно, наиболее интуитивный, учитывая название):
Мало того, но если строка заканчивается пробелом, она добавляется к следующему:
<*> Очевидно, что -L
не касается изменения способа, которым xargs разделяет входные данные на аргументы.
Единственный аргумент, который делает это кроссплатформенным способом (исключая расширения GNU), это -0
, который разбивает входные данные вокруг байтов NUL.
Тогда нужно просто переводить строки в NUL с помощью tr
:
Теперь разбор аргументов выглядит хорошо, включая завершающий пробел.
Наконец, если вы объедините эту технику с -n 1
, вы получите ровно одно выполнение команды на каждую строку ввода, независимо от того, какой у вас ввод, что может быть еще одним способом взглянуть на исходный вопрос ( возможно, наиболее интуитивный, учитывая название):
Очевидно, что -L
не касается изменения способа, которым xargs разделяет входные данные на аргументы.
Единственный аргумент, который делает это кроссплатформенным способом (исключая расширения GNU), это -0
, который разбивает входные данные вокруг байтов NUL.
Тогда нужно просто переводить строки в NUL с помощью tr
:
Теперь разбор аргументов выглядит хорошо, включая завершающий пробел.
Наконец, если вы объедините эту технику с -n 1
, вы получите ровно одно выполнение команды на каждую строку ввода, независимо от того, какой у вас ввод, что может быть еще одним способом взглянуть на исходный вопрос ( возможно, наиболее интуитивный, учитывая название):
Мало того, но если строка заканчивается пробелом, она добавляется к следующему:
<*> Очевидно, что -L
не касается изменения способа, которым xargs разделяет входные данные на аргументы.
Единственный аргумент, который делает это кроссплатформенным способом (исключая расширения GNU), это -0
, который разбивает входные данные вокруг байтов NUL.
Тогда нужно просто переводить строки в NUL с помощью tr
:
Теперь разбор аргументов выглядит хорошо, включая завершающий пробел.
Наконец, если вы объедините эту технику с -n 1
, вы получите ровно одно выполнение команды на каждую строку ввода, независимо от того, какой у вас ввод, что может быть еще одним способом взглянуть на исходный вопрос ( возможно, наиболее интуитивный, учитывая название):
Теперь разбор аргументов выглядит хорошо, включая завершающий пробел.
Наконец, если вы объедините эту технику с -n 1
, вы получите ровно одно выполнение команды на каждую строку ввода, независимо от того, какой у вас ввод, что может быть еще одним способом взглянуть на исходный вопрос ( возможно, наиболее интуитивный, учитывая название):
Мало того, но если строка заканчивается пробелом, она добавляется к следующему:
<*> Очевидно, что -L
не касается изменения способа, которым xargs разделяет входные данные на аргументы.
Единственный аргумент, который делает это кроссплатформенным способом (исключая расширения GNU), это -0
, который разбивает входные данные вокруг байтов NUL.
Тогда нужно просто переводить строки в NUL с помощью tr
:
Теперь разбор аргументов выглядит хорошо, включая завершающий пробел.
Наконец, если вы объедините эту технику с -n 1
, вы получите ровно одно выполнение команды на каждую строку ввода, независимо от того, какой у вас ввод, что может быть еще одним способом взглянуть на исходный вопрос ( возможно, наиболее интуитивный, учитывая название):
Очевидно, что -L
не касается изменения способа, которым xargs разделяет входные данные на аргументы.
Единственный аргумент, который делает это кроссплатформенным способом (исключая расширения GNU), это -0
, который разбивает входные данные вокруг байтов NUL.
Тогда нужно просто переводить строки в NUL с помощью tr
:
Теперь разбор аргументов выглядит хорошо, включая завершающий пробел.
Наконец, если вы объедините эту технику с -n 1
, вы получите ровно одно выполнение команды на каждую строку ввода, независимо от того, какой у вас ввод, что может быть еще одним способом взглянуть на исходный вопрос ( возможно, наиболее интуитивный, учитывая название):
Мало того, но если строка заканчивается пробелом, она добавляется к следующему:
<*> Очевидно, что -L
не касается изменения способа, которым xargs разделяет входные данные на аргументы.
Единственный аргумент, который делает это кроссплатформенным способом (исключая расширения GNU), это -0
, который разбивает входные данные вокруг байтов NUL.
Тогда нужно просто переводить строки в NUL с помощью tr
:
Теперь разбор аргументов выглядит хорошо, включая завершающий пробел.
Наконец, если вы объедините эту технику с -n 1
, вы получите ровно одно выполнение команды на каждую строку ввода, независимо от того, какой у вас ввод, что может быть еще одним способом взглянуть на исходный вопрос ( возможно, наиболее интуитивный, учитывая название):
Если вы хотите запустить команду для каждый линия (т.е.результат), исходящий от find
, тогда для чего вам нужен xargs
для чего?
Попробуй:
find
путь -type f -exec
ваше-командование {} \;
где буквальный {}
заменяется именем файла и литералом \;
необходим для find
знать, что пользовательская команда заканчивается на этом.
Редактировать:
(после редактирования вашего вопроса, уточняющего, что вы знаете о -exec
)
От man xargs
:
-L максимальное количество линий
Используйте максимум максимальное количество линий непустые строки ввода для каждой командной строки.Завершающий пробелы приводят к логическому продолжению строки ввода на следующей строке ввода.Подразумевает -x.
Обратите внимание, что имена файлов, заканчивающиеся пробелами, могут вызвать у вас проблемы, если вы используете xargs
:
$ mkdir /tmp/bax; cd /tmp/bax
$ touch a\ b c\ c
$ find . -type f -print | xargs -L1 wc -l
0 ./c
0 ./c
0 total
0 ./b
wc: ./a: No such file or directory
Так что, если вас не волнует -exec
вариант, который вам лучше использовать -print0
и -0
:
$ find . -type f -print0 | xargs -0L1 wc -l
0 ./c
0 ./c
0 ./b
0 ./a
Как я могу заставить xargs выполнять команду ровно один раз для каждой заданной строки ввода?
Я не использую ответ -L 1
, потому что он не обрабатывает файлы с пробелами, что является ключевой функцией find -print0
.
echo "file with space.txt" | xargs -L 1 ls
ls: file: No such file or directory
ls: space.txt: No such file or directory
ls: with: No such file or directory
Лучшее решение - использовать tr
для преобразования новых строк в нулевые ( \ 0
) символы, а затем использовать аргумент xargs -0
. р>
echo "file with space.txt" | tr '\n' '\0' | xargs -0 ls
file with space.txt
Если вам необходимо ограничить количество вызовов, вы можете использовать аргумент -n 1
, чтобы сделать один вызов программы для каждого ввода:
echo "file with space.txt" | tr '\n' '\0' | xargs -0 -n 1 ls
Это также позволяет вам фильтровать вывод команды find перед преобразованием разрывов в нули.
find . -name \*.xml | grep -v /workspace/ | tr '\n' '\0' | xargs -0 tar -cf xml.tar
Еще одна альтернатива ...
find /path -type f | while read ln; do echo "processing $ln"; done
find path -type f | xargs -L1 command
это все, что вам нужно.
Эти два способа также работают и будут работать для других команд, которые не используют find!
xargs -I '{}' rm '{}'
xargs -i rm '{}'
пример использования:
find . -name "*.pyc" | xargs -i rm '{}
удалит все файлы pyc в этом каталоге, даже если файлы pyc содержат пробелы.
Следующая команда найдет все файлы (-type f) в / path
, а затем скопирует их, используя cp
, в текущую папку. Обратите внимание на использование if -I%
для указания символа-заполнителя в командной строке cp
, чтобы аргументы можно было размещать после имени файла.
find / path -type f -print0 | xargs -0 -I% cp%.
Протестировано с xargs (GNU findutils) 4.4.0
Вы можете ограничить количество строк или аргументов (если между аргументами есть пробелы), используя флаги --max-lines или --max-args соответственно.
-L max-lines Use at most max-lines nonblank input lines per command line. Trailing blanks cause an input line to be logically continued on the next input line. Implies -x. --max-lines[=max-lines], -l[max-lines] Synonym for the -L option. Unlike -L, the max-lines argument is optional. If max-args is not specified, it defaults to one. The -l option is deprecated since the POSIX standard specifies -L instead. --max-args=max-args, -n max-args Use at most max-args arguments per command line. Fewer than max-args arguments will be used if the size (see the -s option) is exceeded, unless the -x option is given, in which case xargs will exit.
Кажется, у меня недостаточно репутации, чтобы добавить комментарий к ответу Тобиа выше , поэтому я добавляю это & Quot; ответ & Quot; чтобы помочь тем из нас, кто хочет поэкспериментировать с xargs
на платформах Windows.
Вот пакетный файл Windows, который делает то же самое, что и быстро закодированный "show", показанный Tobia. Сценарий:
@echo off
REM
REM cool trick of using "set" to echo without new line
REM (from: http://www.psteiner.com/2012/05/windows-batch-echo-without-new-line.html)
REM
if "%~1" == "" (
exit /b
)
<nul set /p=Args: "%~1"
shift
:start
if not "%~1" == "" (
<nul set /p=, "%~1"
shift
goto start
)
echo.
@Draemon отвечает правильно с " -0 " даже с пробелом в файле.
Я пробовал команду xargs и обнаружил, что " -0 " отлично работает с < -L " ;. обрабатываются даже пробелы (если ввод был завершен нулем). Ниже приведен пример:
#touch "file with space"
#touch "file1"
#touch "file2"
Следующее разделит пустые значения и выполнит команду для каждого аргумента в списке:
#find . -name 'file*' -print0 | xargs -0 -L1
./file with space
./file1
./file2
поэтому -L1
будет выполнять аргумент для каждого символа с нулевым символом в конце, если используется с " -0 " ;. Чтобы увидеть разницу, попробуйте:
#find . -name 'file*' -print0 | xargs -0 | xargs -L1
./file with space ./file1 ./file2
даже это будет выполнено один раз:
#find . -name 'file*' -print0 | xargs -0 | xargs -0 -L1
./file with space ./file1 ./file2
Команда будет выполнена один раз как " -L " теперь не разделяется на нулевой байт. вам нужно указать оба параметра "-0" и < -L " работать. Р>
В вашем примере смысл передачи вывода find в xargs заключается в том, что стандартное поведение параметра find -exec состоит в том, чтобы выполнить команду один раз для каждого найденного файла. Если вы используете find и хотите использовать его стандартное поведение, тогда ответ прост - не используйте xargs для начала.
выполните очистку муравьиной задачи для каждого файла build.xml в текущей или вложенной папке.
find . -name 'build.xml' -exec ant -f {} clean-all \;