grep файли зі списку


14

Я намагаюся запустити grep проти списку кількох сотень файлів:

$ head -n 3 <(cat files.txt)
admin.php
ajax/accept.php
ajax/add_note.php

Однак, хоча я шукаю рядок, який, як я знаю, знайдений у файлах, наступне не шукає файли:

$ grep -i 'foo' <(cat files.txt)

$ grep -i 'foo' admin.php
The foo was found

Мені знайомий -fпрапор, який буде читати шаблони з файлу. Але як читати вхідні файли ?

Я вважав жахливим вирішенням копіювання файлів у тимчасовий каталог, як cpздається, підтримує <(cat files.txt)формат, і звідти схоплюючи файли. У Ширлі є кращий спосіб.

Відповіді:


22

Ви ніби переглядаєте список імен файлів, а не самі файли. <(cat files.txt)просто перелічує файли. Спробуйте <(cat $(cat files.txt))насправді об'єднати їх і шукати їх як єдиний потік, або

grep -i 'foo' $(cat files.txt)

дати grep всі файли.

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

while read filename; do grep -Hi 'foo' "$filename"; done < files.txt

Дякую! Я не розумів, що whileможе отримати рядки file.txt як такий.
dotancohen

Тут ви захочете відключити глобальну частину цього оператора split + glob (якщо оболонка не є zsh).
Стефан Шазелас

1
whileне точно отримує рядки з файлу, readробить це; whileпросто дозволяє нам це робити в циклі. Цикл закінчується, коли readне вдається (тобто повертає ненульовий код повернення), як правило, внаслідок досягнення кінця файлу.
PM 2Ring

1
Для того, щоб прочитати рядок (текст), синтаксис IFS= read -r filename, read filenameце щось інше.
Стефан Шазелас

1
Зауважте, що -Hце розширення GNU. Ти дещо пропускаєш --.
Стефан Шазелас

8
xargs grep -i -- foo /dev/null < files.txt

припустимо, що файли є порожніми чи новими рядками (де цитати або зворотні косої риси можна використовувати для виходу з цих роздільників). За допомогою GNU xargsви можете вказати роздільник з -d(який потім відключає обробку котирування).

(unset -v IFS; set -f; grep -i -- foo $(cat files.txt))

припустимо, що файли розділені пробілом, вкладками або новою лінією (жодного способу не уникнути тих, хоча ви можете вибрати інший роздільник, призначивши його IFS). Це не вдасться, якщо список файлів занадто великий у більшості систем.

Вони також припускають, що жоден з файлів не викликається -.


Краще / швидше використовувати $(< file)замість $(cat file), принаймні, в bashі zsh.
jimmij

7

Щоб прочитати список імен файлів від stdin ви можете використовувати xargs. Наприклад,

cat files.txt | xargs -d'\n' grep -i -- 'foo'

За замовчуванням xargsчитає елементи зі стандартного вводу, розділені пробілами. -d'\n'Каже , що використовувати символ нового рядка в якості аргументу роздільником, тому він може обробляти імена файлів , що містять пробіли. (Як зазначає Стефан Шазелас, це розширення GNU). Однак він не впорається з іменами файлів, що містять нові рядки; нам потрібен трохи складніший підхід для вирішення цих питань.

FWIW, такий підхід дещо швидший, ніж while readцикл, оскільки readкоманда bash дуже повільна - вона читає свій характер даних за символом, тоді як xargsчитає його введення більш ефективно. Крім того, xargsвикликуйте grepкоманду лише стільки разів, скільки потрібно, кожен виклик отримує кілька імен файлів, і це більш ефективно, ніж виклик grepокремо для кожного імені файлу.

Щоб отримати докладнішу інформацію, див. Сторінку людини xargs та інформацію про інформацію xargs.


3

xargsможе читати елементи з файлу (наприклад, у вашому files.txtсписку) за допомогою параметра:

   --arg-file=file
   -a file
          Read items from file instead of standard input.  If you use this
          option, stdin remains unchanged when commands are  run.   Other
          wise, stdin is redirected from /dev/null.

Тож і це має працювати:

xargs -a files.txt grep -i 'foo'

або для пробілів у назви файлів

xargs -d'\n' -a files.txt grep -i 'foo'
xargs -I{} -a files.txt grep -i 'foo' {}

1

Ви також можете зробити для, але приклад Оріона найпростіший:

for i in $(cat files.txt); do grep -i 'foo' $i ; done

(Для кожного файлу, вказаного у файлі files.txt, виконайте команду grep на ньому.)

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