Распараллелить функцию с помощью xargs и отдельных переменных

Предположим, вы хотите добавить содержимое файла templateв файл dataтолько в том случае, если в dataуже нет строки из template.

Команда для проверки того, найдена ли строка в templateв data:

grep -xF -f template data

(Это разумно делать, только если templateсодержит менее нескольких тысяч строк)

Здесь используются следующие опцииgrep:

  • -x, заставляя тестировать полные линии, от начала до конца строки. Без этого мы можем получить ложные срабатывания, если строка в templateсовпадает со строкой в ​​dataчастично (, например, строка hello worldсоответствует hello world!частично ).
  • -F,с использованием сравнения строк, а не сопоставления регулярных выражений. Без этой опции grepбудет обрабатывать строки в templateкак регулярные выражения, что может привести к неправильным результатам, если какая-либо строка шаблона содержит специальные символы в регулярных выражениях.
  • -f template, это заставляет grepиспользовать каждую строку из templateотдельно в качестве шаблонов для сопоставления с каждой строкой в ​​файле data.

Добавление опции -qк этому (, чтобы сделать grepтихим и позволить ему закрыться, как только будет найдено совпадение ), позволяет нам использовать его в простом тесте:

if ! grep -q -xF -f template data; then
    cat template >>data
fi

Тело оператора ifдобавляет файл templateв конец файла dataтолько в том случае, если команде grepне удается найти совпадение каких-либо строк из templateв data.

3
24.05.2021, 10:59
2 ответа

Встраивание {}в шелл-код — всегда плохая идея, так как это приводит к уязвимости, связанной с внедрением команд. Всегда лучше передавать данные как отдельные аргументы (не -кода ).

Также -I, без -d/ -0по-прежнему забивается кавычками и обратной косой чертой и удаляет ведущие пробелы. С GNU xargs(, который вы должны использовать, поскольку вы уже используете -Pрасширение GNU ), лучше всего использовать -d '\n'для передачи каждой строки ввода в качестве отдельного аргумента

xargs -a txt -rd'\n' -P2 -n1 bash -c 'foo "$2" "$1"' bash "$a"

(вызывает один bashвызов для каждой 1строки ввода с содержимым $aи текущей строки в качестве отдельных аргументов, которые упоминаются как $1и $2во встроенном сценарии оболочки ). ].

Или с-I:

xargs -a txt -rd'\n' -P2 -I'{}' bash -c 'foo "$1" "$2"' bash {} "$a"

Здесь вы можете переключиться на zsh, который имеет zargsавтозагружаемую функцию, которая может выполнять параллельную обработку а-ля GNU xargs, включая функции без необходимости запускать отдельные вызовы оболочки или экспортировать функции, как это делает xargs.

$ autoload zargs
$ foo() print -r - $1 is not $2
$ zargs -P2 -I {} {1..4} -- foo {} $a
1 is not foo
2 is not foo
3 is not foo
4 is not foo
6
28.07.2021, 11:29

С GNU Parallel это выглядит так:

foo() { echo "$1 is not $2"; }
export -f foo
seq 4 > txt
a=0
cat txt | parallel foo {} $a
0
28.07.2021, 11:29

Теги

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