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

Во-первых, здесь можно ответить на некоторые из ваших вопросов: Насколько велик буфер канала?

Канал - это ограниченный кольцевой буфер, который поддерживается ядром. Системный вызов pipe создает новый канал и связывает с ним два файловых дескриптора: один для записи в канал, а другой для чтения из канала.

Записывает в конвейер через связанный файловый дескриптор, копирует данные в этот буфер, если для них есть место. Если для данных нет места, вызов write () блокирует вызывающее приложение до тех пор, пока пространство не станет доступным. Если процесс заблокирован в операции write () в канале, а какой-либо другой процесс / поток читает из канала достаточно данных, которые позволят заблокированному записывающему устройству завершить свою запись, то заблокированный писатель пробуждается и ему разрешается продолжить.

Для читателей процесс работает аналогично. Если процесс чтения пытается читать из канала, а там читать нечего, системный вызов read () блокирует ожидание, пока данные станут доступны. Если процесс заблокирован в операции read () на папе, и какой-то другой процесс / поток записывает данные в канал, что позволяет заблокированному считывателю завершить свое чтение, то заблокированный считыватель пробуждается и разрешается продолжить.

Что касается размера трубы, вы можете найти некоторую информацию в следующей записи на странице руководства из man 7 pipe :

Пропускная способность трубы

  Труба имеет ограниченную пропускную способность. Если канал заполнен, то запись (2) 
будет заблокирована или завершится ошибкой, в зависимости от того, установлен ли флаг O_NONBLOCK 
 (см. Ниже). Различные реализации имеют разные ограничения на пропускную способность трубы 
. Приложения не должны полагаться на конкретную емкость 
: приложение должно быть спроектировано таким образом, чтобы процесс чтения 
потреблял данные, как только они становятся доступными, чтобы процесс записи 
не остаются заблокированными. 
 
В версиях Linux до 2.6.11 емкость канала была такой же 
, что и размер системной страницы (например,, 4096 байт на i386). Начиная с Linux 
2.6.11, емкость канала составляет 65536 байт. Начиная с Linux 2.6.35, емкость канала по умолчанию 
составляет 65536 байт, но емкость можно запросить 
и установить с помощью операций fcntl (2) F_GETPIPE_SZ и F_SETPIPE_SZ. 
См. Fcntl (2) для получения дополнительной информации. 
 

Вот пример программы для запроса размера канала:

#define _GNU_SOURCE
#include 
#include 
#include 
#include 
#include 

int main(void)
{
    int pipefds[2] = { -1, -1 };

    assert(pipe(pipefds) == 0);

    printf("pipe size: %d\n", fcntl(pipefds[0], F_GETPIPE_SZ));

    // pipe will be closed on exit
    return EXIT_SUCCESS;
}

Запуск программы дает мне:

$ ./a.out
pipe size: 65536

1
15.06.2016, 04:17
1 ответ

Давайте посмотрим на конвейер:

/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 пытается прочитать весь свой стандартный ввод сразу как единый элемент. Вот почему он генерирует сообщение об ошибке «слишком длинная строка аргумента».

Решение состоит в том, чтобы указать 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, или восьмеричным или шестнадцатеричным escape-кодом. Восьмеричные и шестнадцатеричные escape-коды понимаются как для команды printf. Многобайтовые символы не поддерживаются.

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

2
27.01.2020, 23:35

Теги

Похожие вопросы