xargs: слишком длинная строка аргументов

Когда я запускаю строку ниже в сценарии оболочки:

/sbin/iptables-save -t filter | grep -- "-A INPUT" | grep -v "fail2ban-\|f2b-" | sed -e "s#^-A#apply_rule /sbin/iptables -D#g" | xargs -0 echo -e "`declare -f apply_rule`\n" | /bin/bash 

Все, что он делает, это проверка

 -A INPUT -s IP -j DROP 

правило в iptables-save .

Сказать,

 -A INPUT -s 198.55.114.215 -j DROP 

Затем преобразуйте его в « Delete версию» и перейдите к xargs

 apply_rule /sbin/iptables -D INPUT -s 198.55.114.215 -j DROP 

Но у меня есть правила 2000 -A в iptables-save и когда я пытаюсь запустить его, над строкой выдается ошибка:

 xargs: argument line too long 

Я проверил ограничения и

 echo $(( $getconf ARG_MAX 

результат:

 2621440 

Эта ошибка не возникает, если правила 1000 -A , но правила 2000 -A в iptables-save создают эту проблему.

Фактическая ошибка – это строка:

 xargs -0 echo -e "`declare -f apply_rule`\n" 

Как я могу исправить эту проблему?

Давайте посмотрим на трубопровод:

 /sbin/iptables-save -t filter | grep -- "-A INPUT" | grep -v "fail2ban-\|f2b-" | sed -e "s#^-A#apply_rule /sbin/iptables -D#g" | xargs -0 echo -e "`declare -f apply_rule`\n" | /bin/bash 

iptables генерирует список правил, по одному правилу на строку. Другими словами, каждое правило разделяется символом новой строки \n . С параметрами, как показано, команды grep и sed обрабатывают свои входные данные по одной строке за раз. Другими словами, они также ожидают ввод данных, разделенных символом новой строки, и вывод данных, разделенных символом линии. xargs -0 ожидает вход с xargs -0 разделением. Поскольку вывод команд, которые предшествуют, не содержит nul-символов, xargs пытается сразу прочитать весь свой stdin как отдельный элемент. Именно поэтому он генерирует сообщение об ошибке «слишком длинная строка аргументов».

Решение состоит в том, чтобы сказать xargs ожидать ввода, разделенного символом новой строки. Для этого добавим параметр -d '\n' . Однако мы также хотим, чтобы он обрабатывал только одну строку за раз. Для этого нам нужно указать -n1 . Объединяя это все вместе:

 /sbin/iptables-save -t filter | grep -- "-A INPUT" | grep -v "fail2ban-\|f2b-" | sed -e "s#^-A#apply_rule /sbin/iptables -D#g" | xargs -n1 -d '\n' echo -e "`declare -f apply_rule`\n" | /bin/bash 

Документация

От man xargs :

-d delim
Элементы ввода заканчиваются указанным символом. Котировки и обратная косая черта не являются особенными; каждый символ ввода вводится буквально. Отключает строку конца файла, которая рассматривается как любой другой аргумент. Это можно использовать, когда вход состоит из простых элементов, разделенных символом новой строки, хотя почти всегда лучше разрабатывать вашу программу для использования –null, где это возможно. Указанный разделитель может быть единственным символом, escape-символом типа C, таким как \ n или восьмеричным или шестнадцатеричным кодом возврата. Октальные и шестнадцатеричные коды возврата понимаются как команда printf. Многобайтные символы не поддерживаются.

-n max-args
Используйте максимум аргументов max-args для командной строки. Если параметр размера (см. Параметр -s) превышен, будет меньше аргументов max-args, если не указана опция -x, и в этом случае xargs выйдут.