Linux. Утилита xargs

03.12.2022

Теги: BashCLILinuxКоманда

Утилита 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

Поиск: CLI • Linux • Команда • xargs

Каталог оборудования
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Производители
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Функциональные группы
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.