Як обробити кожен рядок, отриманий в результаті команди grep


152

У мене є ряд рядків, витягнутих з файлу після виконання команди grep таким чином:

var=`grep xyz abc.txt`

Скажімо, я отримав 10 рядків, що складається з xyz.

Тепер мені потрібно обробити кожен рядок, який я отримав у результаті команди grep. Як мені це зробити?


6
Жодна з відповідей тут не згадує силу grep -oтакого роду речей. -oПрапор буде повертати тільки текст , який відповідає, з одного сірника на лінії виходу. (Це не є вичерпним, тому echo aaa |grep 'a*'дає лише "ааа" та опускає три часткові поєдинки "", "а" та "аа")
Адам Кац

Відповіді:


269

Один з найпростіших способів - не зберігати висновок у змінній, а безпосередньо переглядати її через цикл час / читання.

Щось на зразок:

grep xyz abc.txt | while read -r line ; do
    echo "Processing $line"
    # your code goes here
done

Існують варіанти цієї схеми залежно від того, що саме ви хочете.

Якщо вам потрібно змінити змінні всередині циклу (і щоб ця зміна була видимою поза нею), ви можете використовувати підстановку процесу, як зазначено у відповіді fedorqui :

while read -r line ; do
    echo "Processing $line"
    # your code goes here
done < <(grep xyz abc.txt)

якщо немає рядка з xyz?
XYZ_Linux

Тоді нічого не відбувається, цикл не запускається.
Мат

13
Проблема цього методу полягає в тому, що (через трубу) все, що знаходиться всередині циклу, знаходиться в нижній частині корпусу, тому встановлення змінних, визначених поза циклом під час циклу, не надає їх значень після циклу!
Девід Дорія

3
@David: запропонував альтернативу для вирішення ваших проблем. (fedorqui вже до цього звертався.)
Мат

Для команд, останній рядок виводу яких не закінчується новим рядком, вам знадобиться: while read p || [[ -n $p ]]; do ...(запозичено з stackoverflow.com/questions/1521462/… )
Охад Шнайдер,

21

Ви можете зробити наступний while readцикл, який подаватиметься за результатами grepкоманди, використовуючи так звану підстановку процесу:

while IFS= read -r result
do
    #whatever with value $result
done < <(grep "xyz" abc.txt)

Таким чином, вам не потрібно зберігати результат у змінній, а безпосередньо "вводити" його вихід у цикл.


Зверніть увагу на використання IFS=та read -rвідповідно до рекомендацій у BashFAQ / 001: Як я можу прочитати файл (потік даних, змінний) по черзі (та / або поле за полем)? :

Опція -r для читання перешкоджає інтерпретації зворотної косої риси (зазвичай використовується як пара зворотнього косого кута, щоб продовжуватись через декілька рядків або виходити з розмежувачів). Без цієї опції будь-які незмінені риски на вході будуть відкинуті. Ви майже завжди повинні використовувати параметр -r з читанням.

У вищезазначеному сценарії IFS = запобігає обрізанню пробілу та пробілу. Видаліть його, якщо хочете цього ефекту.

Що стосується заміни процесу, то це пояснюється на сторінці хакерів bash :

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


Гаразд, я вразив forверсію. Спробував зробити цикл, "${$(grep xyz abc.txt)[@]}"як у stackoverflow.com/a/14588210/1983854, але не зміг. Тому я просто залишаю першу версію.
fedorqui 'ТАК перестаньте шкодити'

1
Ви не можете застосувати розширення параметрів до підстановки команди (якщо ви не використовуєте zsh, де такий тип вкладення, ймовірно, працює).
чепнер

Одна з можливих проблем з цією ідіомою полягає в тому, що якщо щось, що знаходиться всередині циклу, намагається прочитати зі стандартного вводу, воно отримає частину файлу. Щоб уникнути такої можливості, я люблю надсилати файл через дескриптор файлів 3, а не через stdin. Просто використовуйте while IFS= read -r result <&3іdone 3< <(grep ...
Гордон Девіссон


2

Без будь-якої ітерації з опцією --line-bupper grep:

your_command | grep --line-buffered "your search"

Приклади реального життя з командою налагодження маршрутизатора Symfony PHP Framework для вимкнення всіх "api" маршрутів:

php bin/console d:r | grep --line-buffered "api"

Єдине рішення, яке працює, якщо your_command працює довго (наприклад tail -f some.log, у моєму випадку) ...
Izkata

0

Часто порядок обробки не має значення. Паралель GNU зроблений для цієї ситуації:

grep xyz abc.txt | parallel echo do stuff to {}

Якщо обробка більше схожа на:

grep xyz abc.txt | myprogram_reading_from_stdin

і myprogramповільно, тоді ви можете запустити:

grep xyz abc.txt | parallel --pipe myprogram_reading_from_stdin

0

Ітерація над результатами grep з циклом час / читання. Подібно до:

grep pattern filename.txt | while read -r line ; do
    echo "Matched Line:  $line"
    # your code goes here
done

0

Для тих, хто шукає однолінійку:

grep xyz abc.txt | while read -r line; do echo "Processing $line"; done
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.