Какую задачу решает xargs
Часто нужно проверить не один хост, а десяток: пропинговать список серверов, спросить DNS по списку имён, проверить несколько адресов на открытый порт. Писать команду для каждого вручную долго, а ввод имён в аргументы не всегда получается через конвейер: большинство команд вроде ping читают аргументы из командной строки, а не из стандартного ввода.
xargs связывает эти два мира. Она читает входной поток, делит его на элементы по пробелам и переводам строк и собирает из них вызов команды. Если вызвать xargs без команды, по умолчанию выполняется echo, то есть просто печатаются прочитанные элементы. Это удобная заготовка для проверки: xargs < файл покажет, как именно xargs поймёт содержимое файла.
Дальше примеры построены на файле hosts.txt, в котором по одному имени или адресу в строке: например, 192.0.2.1, 198.51.100.7 и example.com. Такой файл удобно заготовить заранее и держать рядом с другими рабочими заметками.
Подстановка по одному элементу: -n и -I
По умолчанию xargs пытается уместить как можно больше элементов в один вызов команды. Для ping это бессмысленно: команда ожидает один хост. Поэтому используют ключ -n 1, который берёт по одному элементу за вызов: xargs -n 1 ping -c 1 < hosts.txt. Для каждой строки файла будет запущен свой ping с одним пакетом.
Если значение нужно вставить не в конец команды, а в середину, применяют ключ -I с заменяющей строкой, чаще всего фигурными скобками. Пример: xargs -I{} dig +short {} < hosts.txt. Каждая строка файла подставляется вместо {}, и команда запускается один раз на строку. Ключ -I имеет побочный эффект: элементом считается вся строка целиком, а не слово, поэтому пробелы в строке не разделяют аргументы.
Ключ -c у ping в Linux и macOS задаёт число пакетов. Ключ таймаута -W в этих системах означает разное, у Linux секунды, а у macOS миллисекунды, поэтому в переносимых командах его лучше не использовать, а опираться на ключ -c и ожидание по умолчанию.
Ключи xargs, которые пригодятся
Набор ключей небольшой, но каждый решает конкретную проблему.
| Ключ | Что делает |
|---|---|
| -n число | не больше указанного числа аргументов за вызов |
| -I строка | подставляет каждую входную строку вместо заданной строки |
| -P число | запускает несколько команд параллельно |
| -t | печатает каждую команду перед запуском |
| -0 | разделяет входные элементы нулевым байтом |
| -a файл | читает из файла, этот ключ есть у GNU-версии |
Ключ -t удобен для проверки: он выводит в поток ошибок команду точно в том виде, в каком она запускается, и сразу видно, во что превратился ваш список. Ключ -0 нужен, когда имена могут содержать пробелы: на выходе предыдущей команды вместо перевода строки ставят нулевой байт, а xargs его читает. Для списков хостов он обычно не нужен, а для имён файлов часто нужен.
Ключ -P ускоряет проход по списку, но порядок вывода при параллельном запуске перемешивается, а на медленных каналах сразу много запросов могут исказить измерение.
Рабочие примеры для списка хостов
Все примеры предполагают файл hosts.txt с одним хостом в строке.
- Один пакет на каждый хост, по очереди: xargs -n 1 ping -c 1 < hosts.txt. Вывод длинный, поэтому его удобно пропустить через grep.
- Только строка статистики: xargs -n 1 ping -c 1 < hosts.txt | grep 'packets transmitted'. В выводе ping в Linux и macOS есть слова packets transmitted, но формат строки немного различается, и смотреть нужно на ваш результат.
- Адреса по именам: xargs -I{} dig +short {} < hosts.txt. Ключ +short у dig оставляет в ответе только значения.
- Проверка вместе с подписью: xargs -I{} sh -c 'echo "$1"; dig +short "$1"' _ {} < hosts.txt. Для двух действий на элемент удобно вызвать оболочку; значение передано ей как аргумент $1, а не вставлено в текст команды, чтобы необычная строка в файле не превратилась в чужую команду.
- Параллельно по четыре: xargs -n 1 -P 4 ping -c 1 < hosts.txt. Следите за порядком строк в результате: он может не совпадать с порядком в файле.
Если проверка нужна не одноразово, а регулярно, оформите её как маленький скрипт, а не как длинную строку. Но для разовой диагностики связка файла со списком и xargs остаётся короткой и понятной.
Подводные камни со списком
Пустые строки и пробелы по краям. Лишние символы в файле приводят к пустым или искажённым аргументам, и тогда команда ругается на «неправильный хост». Просмотрите файл перед запуском и уберите всё лишнее.
Комментарии. Если вы пометили часть хостов знаком решётки, xargs не знает об этом и передаст такие строки в команду. Отфильтруйте их заранее: grep -v '^#' hosts.txt | xargs -n 1 ping -c 1.
Кавычки в файле. xargs по умолчанию обрабатывает кавычки и обратную косую черту во входных данных, из-за чего необычные имена могут быть восприняты неверно. Для имён файлов используйте пару find -print0 и xargs -0.
Код возврата. Если одна из запущенных команд завершилась ошибкой, xargs завершится с ненулевым кодом, но продолжит обработку остальных элементов. Поэтому после запуска не стоит сразу делать вывод о недоступности хоста по коду самой xargs: смотрите на вывод каждого вызова.
Наконец, ping с недоступным хостом может выполняться заметное время, так что цепочка из многих хостов без -P идёт долго. Для небольших проверок подойдёт ограничение числа пакетов, а подробности работы ping смотрите на странице про его ключи.
Когда вместо xargs лучше цикл
xargs хороша для одной команды на элемент. Если на каждый хост нужно сделать несколько разных действий, добавить условие или собрать результаты в одну строку, понятнее оказывается цикл оболочки: while read h; do ping -c 1 "$h"; done < hosts.txt. Переменная h получает очередную строку, а кавычки вокруг неё защищают значение от разбиения.
Выбор между ними — вопрос удобства, а не правильности. Цикл читается как программа и легко расширяется, xargs короче и умеет запускать команды параллельно ключом -P. Если вы пишете одноразовую проверку в терминале, начните с xargs. Если проверка будет жить в скрипте и со временем обрастёт условиями, цикл окажется удобнее.
Результат в обоих случаях полезно сохранять. Добавьте в конец цепочки tee, и вывод будет виден на экране и попадёт в файл, который потом можно приложить к обращению в поддержку провайдера или сверить с результатом через день.