використовуючи xargs для отримання декількох шаблонів


12

У мене є файл, у якому є терміни, які я хочу сприйняти, при цьому кожен термін має один рядок у файлі. Я думав, що можу це зробити з xargs. Що я можу отримати із прикладів із такої сторінки man

find ./work -print0 | xargs -0 rm

полягає в тому, що xargs додає висновок команди попередньої труби до кінця своїх аргументів. Отже, якщо знахідка повернулася report.doc, то xargs побудували б rm report.doc. Чи правильно це розуміння?

Отже, оскільки я хочу, щоб значення у моєму файлі знаходилися посеред команди grep, мені потрібно вказати заповнювач. Граючи, я намагався {}, але не вийшло:

$> cat strings.txt | xargs grep {} subdirectory/*
grep: string1: No such file or directory
grep: string2: No such file or directory

Чи правильний інструмент xargs? Якщо так, що таке синтаксис?

Відповіді:


17

Так, find ./work -print0 | xargs -0 rmвиконають щось на кшталт rm ./work/a "work/b c" .... Ви можете перевірити echo, find ./work -print0 | xargs -0 echo rmнадрукує команду, яка буде виконуватися (за винятком білого простору, не буде відповідним чином, хоча це echoне покаже).

Щоб xargsпоставити імена в середину, вам потрібно додати -I[string], де [string]саме те, що ви хочете замінити аргументом, у цьому випадку ви б використовували -I{}, наприклад <strings.txt xargs -I{} grep {} directory/*.

Що ви насправді хочете використовувати grep -F -f strings.txt:

-F, --fixed-strings
  Interpret PATTERN as a  list  of  fixed  strings,  separated  by
  newlines,  any  of  which is to be matched.  (-F is specified by
  POSIX.)
-f FILE, --file=FILE
  Obtain  patterns  from  FILE,  one  per  line.   The  empty file
  contains zero patterns, and therefore matches nothing.   (-f  is
  specified by POSIX.)

Так grep -Ff strings.txt subdirectory/*ви знайдете всі входження будь-якого рядка в strings.txtбуквальному значенні, якщо ви випадете з цього -Fпараметра, ви можете використовувати регулярні вирази у файлі. Насправді ви також можете використовувати grep -F "$(<strings.txt)" directory/*. Якщо ви хочете попрактикуватися find, ви можете використовувати останні два приклади у резюме. Якщо ви хочете зробити рекурсивний пошук замість лише першого рівня, у вас є кілька варіантів, також у резюме.

Підсумок:

# grep for each string individually.
<strings.txt xargs -I{} grep {} directory/*

# grep once for everything
grep -Ff strings.txt subdirectory/*
grep -F "$(<strings.txt)" directory/*

# Same, using file
find subdirectory -maxdepth 1 -type f -exec grep -Ff strings.txt {} +
find subdirectory -maxdepth 1 -type f -print0 | xargs -0 grep -Ff strings.txt

# Recursively
grep -rFf strings.txt subdirectory
find subdirectory -type f -exec grep -Ff strings.txt {} +
find subdirectory -type f -print0 | xargs -0 grep -Ff strings.txt

Ви можете скористатися -lопцією, щоб отримати лише ім’я кожного відповідного файлу, якщо вам не потрібно бачити фактичний рядок:

-l, --files-with-matches
  Suppress  normal  output;  instead  print the name of each input
  file from which output would normally have  been  printed.   The
  scanning  will  stop  on  the  first match.  (-l is specified by
  POSIX.)

4

xargsможе бути не найкращим інструментом, який я б запропонував, fgrepякщо ваш файл-рядків-збігів містить лише рядки, а не регулярні вирази.

fgrep -f strings.txt subdirectory/*

Я пропоную fgrepяк традиційний Unix grepі egrepне мав опції "-f". Я вважаю, що в GNU grepі egrepє параметр "-f", тому якщо у вашому файлі є регулярні вирази, ви хочете використовувати версію GNU.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.