menggunakan xargs untuk menangkap beberapa pola

12

Saya memiliki file yang memiliki syarat yang ingin saya terima, dengan setiap istilah menjadi satu baris dalam file tersebut. Saya berpikir saya bisa melakukan ini dengan xargs. Apa yang saya dapat kumpulkan dari contoh-contoh dari halaman manual seperti ini

find ./work -print0 | xargs -0 rm

adalah bahwa xargs menambahkan output dari perintah pre-pipe ke akhir argumennya. Jadi, jika ditemukan kembali report.doc, maka xargs akan dibangun rm report.doc. Apakah pemahaman ini benar?

Jadi karena saya ingin nilai dalam file saya berada di tengah-tengah perintah grep, saya perlu menentukan placeholder. Dalam bermain-main, saya mencoba {}, tetapi tidak berhasil:

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

Apakah xargs alat yang tepat? Jika demikian, apa sintaksinya?

pengguna394
sumber

Jawaban:

17

Ya, find ./work -print0 | xargs -0 rmakan menjalankan sesuatu seperti rm ./work/a "work/b c" .... Anda dapat memeriksa echo, find ./work -print0 | xargs -0 echo rmakan mencetak perintah yang akan dieksekusi (kecuali spasi putih akan lolos dengan tepat, meskipun echotidak akan menunjukkan itu).

Untuk xargsmenempatkan nama di tengah, Anda perlu menambahkan -I[string], di mana [string]Anda ingin diganti dengan argumen, dalam hal ini Anda akan menggunakan -I{}, misalnya <strings.txt xargs -I{} grep {} directory/*.

Apa yang sebenarnya ingin Anda gunakan adalah 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.)

Jadi grep -Ff strings.txt subdirectory/*akan menemukan semua kemunculan string apa pun strings.txtsebagai literal, jika Anda menjatuhkan -Fopsi, Anda dapat menggunakan ekspresi reguler dalam file. Anda juga bisa menggunakannya grep -F "$(<strings.txt)" directory/*. Jika Anda ingin berlatih find, Anda dapat menggunakan dua contoh terakhir dalam ringkasan. Jika Anda ingin melakukan pencarian rekursif, bukan hanya level pertama, Anda memiliki beberapa opsi, juga dalam ringkasan.

Ringkasan:

# 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

Anda mungkin ingin menggunakan -lopsi untuk mendapatkan hanya nama dari setiap file yang cocok jika Anda tidak perlu melihat baris yang sebenarnya:

-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.)
Kevin
sumber
4

xargsmungkin bukan alat terbaik yang saya sarankan fgrepjika file-of-string-to-match Anda hanya berisi string, bukan ekspresi reguler.

fgrep -f strings.txt subdirectory/*

Saya sarankan fgrepsebagai Unix tradisional grepdan egreptidak memiliki opsi "-f". Saya percaya bahwa GNU grepdan egrepmemang memiliki opsi "-f", jadi jika file Anda memiliki ekspresi reguler di dalamnya, Anda ingin menggunakan versi GNU.

Bruce Ediger
sumber