Linux. Утилита xargs
Утилита xargs
позволяет выполнять команды с аргументами из стандартного ввода или из файла. Обычно используется в сочетании с другими командами через конвейер. Использование xargs
позволяет передать вывод одной команды в качестве аргументов второй команды.
$ первая_команда | xargs [опции] вторая_команда
Утилита xargs
разбивает вывод первой команды на отдельные строки по пробелам или символам новой строки. После чего вызывает вторую команду, передавая ей в качестве аргументов вывод первой команды. По умолчанию вывод первой команды целиком передается в качестве аргумента второй команды. Но с помощью опций можно настроить передачу аргументов небольшими порциями — тогда вторая команда будет вызвана несколько раз. Если вторая команда не указана, по умолчанию используется /bin/echo
.
Давайте создадим три файла
$ echo "file1 file2 file3" | xargs touch $ ls file1 file2 file3
Давайте теперь их удалим
$ ls | xargs rm
Опции утилиты
Чтобы вывести вторую команду на терминал перед ее выполнением — используем опцию -t
или --verbose
$ echo "file1 file2 file3" | xargs -t touch touch file1 file2 file3 $ ls file1 file2 file3
Чтобы получить подтверждение выполнения второй команды — используем опцию -p
или --interactive
$ echo "file1 file2 file3" | xargs -p touch touch file1 file2 file3 ?...n
Эта опция полезна при выполнении потенциально опасных команд.
Опция -n
или --max-args
указывает количество аргументов, передаваемых второй команде. Вторая команда будет вызываться несколько раз, пока не закончатся все аргументы.
$ ls | xargs -n1 -t rm rm file1 rm file2 rm file3
Чтобы не удалить лишнего — можно запрашивать разрешение на удаление каждого файла
$ ls | xargs -n1 -p rm rm file1 ?...n rm file2 ?...y rm file3 ?...y
Опция -l
или --max-lines
указывает количество строк, передаваемых одной команде. Это в какой-то мере похоже на использование опции --max-args
. Вывод первой команды может содержать несколько строк, разделенных символом перевода строки. А каждая строка может содержать несколько слов, разделенных пробелами.
$ ls 'file one' 'file two' 'file three'
$ ls | xargs -p rm rm file one file two file three ?...y rm: невозможно удалить 'file': Нет такого файла или каталога rm: невозможно удалить 'one': Нет такого файла или каталога rm: невозможно удалить 'file': Нет такого файла или каталога rm: невозможно удалить 'two': Нет такого файла или каталога rm: невозможно удалить 'file': Нет такого файла или каталога rm: невозможно удалить 'three': Нет такого файла или каталога
Первая попытка удаления файлов была неудачной, давайте попробуем еще раз — укажем, что передавать rm
надо строку целиком.
$ ls | xargs -p -l1 rm rm file one ?...y rm: невозможно удалить 'file': Нет такого файла или каталога rm: невозможно удалить 'one': Нет такого файла или каталога rm file two ?...y rm: невозможно удалить 'file': Нет такого файла или каталога rm: невозможно удалить 'two': Нет такого файла или каталога rm file three ?...y rm: невозможно удалить 'file': Нет такого файла или каталога rm: невозможно удалить 'three': Нет такого файла или каталога
Опять неудача! Нам нужно, чтобы имена файлов, состоящие из нескольких слов, были заключены в кавычки. Давайте попробуем еще раз.
$ ls | xargs -p -i rm {} rm 'file one' ?...y rm 'file two' ?...y rm 'file three' ?...y
Опция -i
или --replace
позволяет не просто передать второй команде аргументы из вывода первой команды, а вставить их в конкретное место, обозначенное двумя фигурными скобками {}
. Причем вывод первой команды ls
будет разбиваться только по символу новой строки.
$ printf '%s\n' file1 file2 file3 | xargs --verbose --replace bash -c 'touch {}; echo "content of file {}" > {}; cat {}' bash -c 'touch file1; echo "content of file file1" > file1; cat file1' content of file file1 bash -c 'touch file2; echo "content of file file2" > file2; cat file2' content of file file2 bash -c 'touch file3; echo "content of file file3" > file3; cat file3' content of file file3
Важный момент — при использовании опции -i
или --replace
утилита xargs
будет разбивать вывод первой команды на отдельные строки только по символам новой строки. Поэтому в примере выше мы используем printf
, чтобы между именами файлов был символ новой строки. Мы создаем три новых файла, в каждый записываем строку и выводим содержимое каждого файла.
Вместо двух фигурных скобок {}
можно использовать любую строку, если указать ее в качестве значения опции -i
или --replace
.
$ ls 'file one' 'file two'
$ ls | xargs -p -l1 -iARG rm ARG rm 'file one' ?...n rm 'file two' ?...n
$ ls | xargs -p -l1 --replace=ARG rm ARG rm 'file one' ?...n rm 'file two' ?...n
Опции --max-lines
(или -l
), --replace
(или -i
) и --max-args
(или -n
) являются взаимоисключающими. Если некоторые из них указаны одновременно, тогда xargs
будет использовать опцию, указаную последней в командной строке.
Исключением из этого правила является указание опции -n
со значением 1
после опции -i
— в этом случае опция -n
игнорируется.
Опция -d
или --delimiter
позволяет задать другой разделитель вместо пробела.
$ echo -n "file1,file2,file3" | xargs -d ',' -n1 -t touch touch file1 touch file2 touch file3
Обратите внимание на опцию -n
для echo
, которая запрещает вывод символа новой строки после "file1,file2,file3"
. Без этой опции последний аргумент будет не таким file3
, а вот таким 'file3'$'\n'
.
Опция -a
или --arg-file
позволяет читать аргументы из файла вместо стандартного ввода.
$ cat ips.txt 8.8.8.8 1.1.1.1
$ xargs -t -l1 -a ips.txt ping -c1 ping -c1 8.8.8.8 PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data. 64 bytes from 8.8.8.8: icmp_seq=1 ttl=109 time=28.0 ms .......... ping -c1 1.1.1.1 PING 1.1.1.1 (1.1.1.1) 56(84) bytes of data. 64 bytes from 1.1.1.1: icmp_seq=1 ttl=57 time=10.8 ms ..........
Вместе с find
Утилита xargs
чаще всего используется в сочетании с командой find
. Команда find
позволяет найти определенные файлы, а xargs
— выполнинить над ними нужные операции.
Чтобы избежать проблем с именами файлов, которые содержат пробелы, нужно использовать опцию -print0
, которая заставит find
выводить имя файла с нулевым символом в конце. Этот вывод может быть правильно интерпретирован xargs
с помощью опции -0
или --null
.
Удалить временные файлы, которые не изменялись более 7 дней
$ find /tmp -type f -mtime +7 -print0 | xargs --null rm -f
Параллельный запуск
Утилита позволяет запустить параллельно нескольких команд. Для этого используется опция -P
или --max-procs
, которая указывает максимальное количество процессов, которые будут выполняться одновременно.
Запустим архивирование нескольких больших файлов
$ fallocate -l 100M large-size-1.txt $ fallocate -l 100M large-size-2.txt $ fallocate -l 100M large-size-3.txt $ ls -la итого 307208 drwxrwxr-x 2 evgeniy evgeniy 4096 июн 14 13:25 . drwxr-x--- 22 evgeniy evgeniy 4096 июн 14 13:06 .. -rw-rw-r-- 1 evgeniy evgeniy 104857600 июн 14 13:25 large-size-1.txt -rw-rw-r-- 1 evgeniy evgeniy 104857600 июн 14 13:25 large-size-2.txt -rw-rw-r-- 1 evgeniy evgeniy 104857600 июн 14 13:25 large-size-3.txt
$ ls | xargs -n1 --max-procs=3 gzip $ ls -la итого 308 drwxrwxr-x 2 evgeniy evgeniy 4096 июн 14 13:26 . drwxr-x--- 22 evgeniy evgeniy 4096 июн 14 13:06 .. -rw-rw-r-- 1 evgeniy evgeniy 101808 июн 14 13:25 large-size-1.txt.gz -rw-rw-r-- 1 evgeniy evgeniy 101808 июн 14 13:25 large-size-2.txt.gz -rw-rw-r-- 1 evgeniy evgeniy 101808 июн 14 13:25 large-size-3.txt.gz
Рекомендуется использовать опцию -n
или -l
— в противном случае есть вероятность, что команда будет запущена только один раз.
Примеры
Изменить имена всех файлов в директории, добавив в конце расширение .tmp
$ ls one.txt two.txt
$ ls | xargs -t -i mv {} {}.tmp mv one.txt one.txt.tmp mv two.txt two.txt.tmp
$ ls | sed "s/^.*$/& &.tmp/" | xargs -t -n2 mv mv one.txt one.txt.tmp mv two.txt two.txt.tmp
Сохранить все файлы в архив в директории backup
, после чего удалить их все
$ ls one.txt two.txt
$ ls | tr '\n' ' ' | xargs -t -i bash -c 'tar -zcf ~/backup/$(date +%Y.%m.%d-%H.%M.%S).tar.gz {} && rm {}' bash -c 'tar -zcf ~/backup/$(date +%Y.%m.%d-%H.%M.%S).tar.gz one.txt two.txt && rm one.txt two.txt '
$ ls ~/backup/ 2022.12.01-09.00.07.tar.gz 2022.12.02-09.00.05.tar.gz 2022.12.03-09.00.06.tar.gz
Обратите внимание, что команда ls
разделяет вывод файлов символами перевода строки. А поскольку используется опция -i
— утилита xargs
будет разбивать на строки отдельные имена файлов. Нам же нужно получить все имена файлов одной строкой, чтобы передать их tar
и rm
. Поэтому с помощью команды tr
заменяем перевод строки на пробел.
Справка
Справку по использованию утилиты можно получить с помощью опции --help
.
$ xargs --help Использование: xargs [ПАРАМЕТР]… КОМАНДА [НАЧАЛЬНЫЕ-АРГУМЕНТЫ]… Выполняет КОМАНДУ с аргументами НАЧАЛЬНЫЕ-АРГУМЕНТЫ и дополнительными аргументами, прочитанными из стандартного ввода. Обязательность или необязательность аргументов для длинного параметра аналогична и для соответствующего короткого параметра. -0, --null Элементы разделяются null, а не пробельным символом. Отключается обработка кавычек, обратной косой черты и логического EOF -a, --arg-file=ФАЙЛ Читать аргументы из ФАЙЛа, а не стандартного ввода -d, --delimiter=СИМВОЛ Входные элементы разделяются СИМВОЛом, а не пробельным символом. Отключается обработка кавычек, обратной косой черты и логического EOF -E END Задаёт логический EOF строки. Если в входных данных встречается END в виде строки, то оставшиеся входные данные игнорируются (игнорируются, если указан -0 или -d) -e [END], --eof[=END] Эквивалентно -E END, если указан END. Иначе, строка конец-файла отсутствует -I R тоже, что и --replace=R -i,--replace=[R] Заменить R в НАЧАЛЬНЫХ-АРГУМЕНТАХ именами, прочитанными из стандартного ввода. Если R не не указан, то предполагается {} -L,-l, --max-lines=MAX-LINES Использовать не более MAX-LINES непробельных входных строк на командную строку -l[MAX-LINES] Подобен -L, но по умолчанию используется не более одной непробельной входной строки на командную строку, если не указан MAX-LINES -n, --max-args=MAX-ARGS Использовать не более MAX-ARGS аргументов на на командую строку -o, --open-tty Reopen stdin as /dev/tty in the child process before executing the command; useful to run an interactive application. -P, --max-procs=MAX-PROCS Выполнять до MAX-PROCS процессов одновременно -p, --interactive Спрашивать перед выполнением команд --process-slot-var=VAR Добавлять переменную окружения VAR в процессы-потомки -r, --no-run-if-empty Если аргументы не указаны, то КОМАНДУ не выполнять. Если не указан этот параметр, то КОМАНДА будет выполнена не менее одного раза. -s, --max-chars=MAX-CHARS Ограничить длину командной строки до MAX-CHARS --show-limits Показать ограничения на длину командной строки -t, --verbose Выводить команды перед их выполнением -x, --exit Выйти, если превышен размер (см. -s) --help Показать эту справку и выйти --version output version information and exit