Xargs во второй конец трубы?

Debian недавно перешёл на использование network-manager в качестве способа конфигурирования сетевых интерфейсов по умолчанию. Либо настройте сеть с помощью network-manager, либо убедитесь, что /etc/init.d/networking будет вызван в последовательности запуска init, иначе содержимое /etc/network/interfaces не будет иметь значения.

Выполните ls -l /etc/rc[1-5].d/ | grep net и убедитесь, что вы видите что-то вроде следующего:

lrwxrwxrwx 1 root root  25 Oct  2  2014 S01networking -> ../init.d/networking

Если это подтвердится, посмотрите dmesg | grep eth0, но замените eth0 именем сетевого адаптера на виртуальной машине. Сообщите о всех ошибках.

Если вы не видите ссылки на скрипт инициализации сети или видите вместо него network-manager, выполните следующие действия от имени root:

update-rc.d networking defaults
update-rc.d -f network-manager remove

Это позволит установить нужные символические ссылки в /etc/rc[1-6].d/ и отключить network-manager.

Чтобы вручную установить символическую ссылку, вы можете указать ей запуск на любом уровне выполнения 1-5. Например:

pushd /etc/rc1.d/ && ln -s ../init.d/networking S08networking && popd
for i in `seq 2 5` ; do push /etc/rc$i.d/ && ln -s ../init.d/networking S01networking && popd ; done
pushd /etc/rc6.d/ && ln -s ../init.d/networking K07networking && popd
pushd /etc/rc0.d/ && ln -s ../init.d/networking K07networking && popd

Чтобы вручную отключить network-manager сделайте:

rm /etc/rc*.d/S*network-manager
5
22.04.2017, 18:49
2 ответа

Это потому, что вам нужна оболочка, чтобы создать трубу или выполнить перенаправление. Обратите внимание, что cat - это команда для конкатенации, не имеет смысла использовать ее только для одного файла.

cat file1.txt | xargs -I{} sh -c 'cat file2.txt | grep -e "$1"' sh {}

Не делать:

cat file1.txt | xargs -I{} sh -c 'cat file2.txt | grep -e {}'

так как это будет равносильно уязвимости инъекции команд. {} будет расширен в аргументе кода для sh и интерпретирован как код оболочки. Например, если бы в строке file1.txt было $(reboot), это вызвало бы reboot.

Ключ -e (или вы также можете использовать --) также важен. Без него у вас будут проблемы с regexps, начинающимися с --.

Вы можете упростить вышеописанное, используя перенаправления вместо cat:

< file1.txt xargs -I{} sh -c '< file2.txt grep -e "$1"' sh {}

Или просто передать имена файлов в качестве аргумента в grep вместо использования перенаправлений, в этом случае вы можете даже отказаться от sh:

< file1.txt xargs -I{} grep -e {} file2.txt

Вы также можете указать grep искать все регексы сразу в одном вызове:

grep -f file1.txt file2.txt

Заметьте, однако, что в этом случае, это только один регексп для каждой строки file1. txt, нет никакой специальной обработки кавычек, выполняемой xargs.

xargs по умолчанию рассматривает свой ввод как список пустых (в некоторых реализациях только пробел и табуляция, в других - любых символов из класса [:blank:] текущей локали) или разделенных новой строкой слов, для которых можно использовать обратную косую черту, одинарные и двойные кавычки для экранирования разделителей (новая строка может быть экранирована только обратной косой чертой) или друг друга.

Например, при вводе типа:

 'a "b'\" "bar baz" x\
y

xargs без -I{} команде будут переданы a "b", bar baz и xy.

С -I{}, xargs получает одно слово в строке, но все же выполняет некоторую дополнительную обработку. Он игнорирует ведущие (но не последующие) пробелы. Пробелы больше не рассматриваются как разделители, но обработка кавычек все равно выполняется.

На приведенном выше xargs -I{} передаст команде один a "b" foo bar xy аргумент. Также обратите внимание, что во многих системах, как того требует POSIX, это не будет работать, если длина слов превышает 255 символов. В общем, xargs -I{} довольно бесполезен.

Если вы хотите, чтобы каждая строка передавалась дословно как аргумент команды, вы можете использовать расширение GNU xargs -d '\n':

< file1.txt xargs -d '\n' -n 1 grep file2.txt -e

(здесь используется другое расширение GNU grep, которое позволяет передавать опции после аргументов (при условии, что POSIXly correct не находится в окружении) или портативно:

sed "s/'/'\\\\\\''/g;s/.*/'&'/" file1.txt | xargs -n1 sh -c '
  for line do
    grep -e "$line" file2.txt
  done' sh

Если вы хотите, чтобы каждое слово в file1. txt (кавычки все еще распознаются), а не каждую строку (что также обойдет вашу проблему с пробелами в конце строки, если у вас все равно одно слово в строке), вы можете использовать xargs -n1 вместо -I:

< file1.txt xargs -n1 sh -c '
  for word do
    grep -e "$word" file2.txt
  done' sh

Чтобы удалить ведущие и последующие пробелы (но без обработки кавычек, которую делает xargs), вы также можете сделать:

unset IFS # restore word splitting to its default
while read -r regexp; do
  grep -e "$regexp" file2.txt
done < file1.txt
15
27.01.2020, 20:31

В зависимости от того, что вы пытаетесь сделать, вам может быть лучше полностью пропустить xargs и вместо этого использовать следующее решение:

grep -f file1.txt file2.txt

Оно отличается от исходного команда (как только мы исправим ее, как в ответе Стефана Чазеласа) следующим образом:

  • Строки печатаются в том порядке, в котором они появляются в file2.txt , независимо от того, каким шаблонам они соответствуют. В вашей команде печатаются все строки, соответствующие первому шаблону, затем все строки, соответствующие второму, и так далее.
  • Строки, соответствующие более чем одному шаблону, печатаются ровно один раз. В вашей команде они печатаются один раз для каждого совпадающего шаблона.
  • Упростить использование нескольких флагов, включая -v и -c .

Флаг -f указан в POSIX и поэтому достаточно переносим.

8
27.01.2020, 20:31

Теги

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