Как включить информацию в строку выше при поиске шаблона в строке?

Мне нужно провести различие между сценариями первого изображения и второго изображения при получении информации с помощью grep. Оба они созданы, но один для изображения, а один для твита. Все те, для твитов, имеют }, в строке выше, поэтому я думал, что могу использовать эту информацию, но я не уверен, как это сделать.

Вот grep, который я использую:

grep -wirnE 'Wed Oct 19 2(1:[0-5][0-9]:[0-5][0-9]|2:([0-2][0-9]:[0-5][0-9]|30:00)) .* 2016' *

1
задан 27 September 2017 в 10:18

4 ответа

Вы можете использовать опции -A1 и -B1, чтобы grep напечатал строку после (-A) и до (-B) соответствующей строки. Попробуйте следующую командную строку:

grep -B1 created_at log-file|grep -A1 '^}'|grep created_at

Я протестировал со следующим входным файлом с именем log-file

asdf qwerty ... }, "created_at" "date-with-near-}" zxcv some other string "created_at" "date-without-}" ...

Последовательность тестирования

$ grep -B1 created_at log-file }, "created_at" "date-with-near-}" -- some other string "created_at" "date-without-}" $ grep -B1 created_at log-file|grep -A1 '^}' }, "created_at" "date-with-near-}" $ grep -B1 created_at log-file|grep -A1 '^}'|grep created_at "created_at" "date-with-near-}"
2
ответ дан 18 July 2018 в 06:09

Вы можете использовать команду sed N для чтения нескольких строк в пространстве шаблонов.

Чтобы найти первый:

sed -nr '/\}/N; /.*\}.*\n.*"Wed Oct 19 .* 2016/Ip' file

и удалить предыдущая строка:

sed -nr '/}/N; s/.*}.*\n(.*"Wed Oct 19 .* 2016)/\1/Ip' file

Проблема в том, что sed не укажет вам, из какого файла находится строка, и у него нет рекурсивного флага поиска файла (afaik). Это можно обойти, включив рекурсивное подталкивание с помощью ** в оболочке (но проблема «какой файл сделал это?»):

shopt -s globstar sed -nrs '/}/N; s/.*}.*\n(.*"Wed Oct 19 .* 2016)/\1/Ip' **

С несколькими файлами добавьте -s, чтобы sed рассматривали поток как отдельные файлы (чтобы избежать нежелательных многострочных совпадений). Вы можете добавить свое подробное выражение в середине ...

sed -nrs '/}/N; s/.*}.*\n(.*"Wed Oct 19 2(1:[0-5][0-9]:[0-5][0-9]|2:([0-2][0-9]:[0-5][0-9]|30:00)) .* 2016)/\1/Ip' **

Для второго появления с нет } в предыдущей строке

sed -nr '/^[^}]*$/N; /.*\n.*"Wed Oct 19 .* 2016/Ip' file

и удалите предыдущую строку:

sed -nr '/^[^}]*$/N; s/.*\n(.*"Wed Oct 19 .* 2016)/\1/Ip' file

Чтобы объединить это в нечто более полезное:

for f in **; do [[ -f "$f" ]] && echo -e ""$f":\n tweet: $(sed -nr '/}/N; s/.*}.*\n(.*"Wed Oct 19 .* 2016)/\1/Ip' "$f")\n image: $(sed -nr '/^[^}]*$/N; s/.*\n(.*"Wed Oct 19 .* 2016)/\1/Ip' "$f")"; done

или ... чуть более читаемо (!)

#!/bin/bash shopt -s globstar for f in **; do [[ -f "$f" ]] && echo -e ""$f":\n tweet: $(sed -nr '/}/N; s/.*}.*\n(.*"Wed Oct 19 .* 2016)/\1/Ip' "$f")" done

Это дает вывод, похожий на:

file1: tweet: "created_at": "Wed Oct 19 12:36:54 +0000 2016" image: "created_at": "Wed Oct 19 somethingsomething 2016" file2: tweet: "created_at": "Wed Oct 19 random-chars 2016" image: "created_at": "Wed Oct 19 whatever 2016"

Если вы хотите исключить тот или иной, удалите соответствующая часть из сценария, например, для получения только твита ...

for f in **; do [[ -f "$f" ]] && echo -e ""$f":\n tweet: $(sed -nr '/}/N; s/.*}.*\n(.*"Wed Oct 19 .* 2016)/\1/Ip' "$f")" done

Примечания

sed -n должны быть тихими, пока мы не попросим выход - это используется в сочетании с команда печати p для имитации действия grep -r использует расширенное регулярное выражение /}/N, найдите строку с } и прочитайте следующую строку в пространстве шаблонов [f 24] найдите строку без } и прочитайте следующую строку в пространстве шаблонов I регистр без учета регистра p распечатайте найденные / отредактированные строки s/old/new замените old на new
2
ответ дан 18 July 2018 в 06:09

Вы можете использовать опции -A1 и -B1, чтобы grep напечатал строку после (-A) и до (-B) соответствующей строки. Попробуйте следующую командную строку:

grep -B1 created_at log-file|grep -A1 '^}'|grep created_at

Я протестировал со следующим входным файлом с именем log-file

asdf qwerty ... }, "created_at" "date-with-near-}" zxcv some other string "created_at" "date-without-}" ...

Последовательность тестирования

$ grep -B1 created_at log-file }, "created_at" "date-with-near-}" -- some other string "created_at" "date-without-}" $ grep -B1 created_at log-file|grep -A1 '^}' }, "created_at" "date-with-near-}" $ grep -B1 created_at log-file|grep -A1 '^}'|grep created_at "created_at" "date-with-near-}"
2
ответ дан 24 July 2018 в 18:31

Вы можете использовать команду sed N для чтения нескольких строк в пространстве шаблонов.

Чтобы найти первый:

sed -nr '/\}/N; /.*\}.*\n.*"Wed Oct 19 .* 2016/Ip' file

и удалить предыдущая строка:

sed -nr '/}/N; s/.*}.*\n(.*"Wed Oct 19 .* 2016)/\1/Ip' file

Проблема в том, что sed не укажет вам, из какого файла находится строка, и у него нет рекурсивного флага поиска файла (afaik). Это можно обойти, включив рекурсивное подталкивание с помощью ** в оболочке (но проблема «какой файл сделал это?»):

shopt -s globstar sed -nrs '/}/N; s/.*}.*\n(.*"Wed Oct 19 .* 2016)/\1/Ip' **

С несколькими файлами добавьте -s, чтобы sed рассматривали поток как отдельные файлы (чтобы избежать нежелательных многострочных совпадений). Вы можете добавить свое подробное выражение в середине ...

sed -nrs '/}/N; s/.*}.*\n(.*"Wed Oct 19 2(1:[0-5][0-9]:[0-5][0-9]|2:([0-2][0-9]:[0-5][0-9]|30:00)) .* 2016)/\1/Ip' **

Для второго появления с нет } в предыдущей строке

sed -nr '/^[^}]*$/N; /.*\n.*"Wed Oct 19 .* 2016/Ip' file

и удалите предыдущую строку:

sed -nr '/^[^}]*$/N; s/.*\n(.*"Wed Oct 19 .* 2016)/\1/Ip' file

Чтобы объединить это в нечто более полезное:

for f in **; do [[ -f "$f" ]] && echo -e ""$f":\n tweet: $(sed -nr '/}/N; s/.*}.*\n(.*"Wed Oct 19 .* 2016)/\1/Ip' "$f")\n image: $(sed -nr '/^[^}]*$/N; s/.*\n(.*"Wed Oct 19 .* 2016)/\1/Ip' "$f")"; done

или ... чуть более читаемо (!)

#!/bin/bash shopt -s globstar for f in **; do [[ -f "$f" ]] && echo -e ""$f":\n tweet: $(sed -nr '/}/N; s/.*}.*\n(.*"Wed Oct 19 .* 2016)/\1/Ip' "$f")" done

Это дает вывод, похожий на:

file1: tweet: "created_at": "Wed Oct 19 12:36:54 +0000 2016" image: "created_at": "Wed Oct 19 somethingsomething 2016" file2: tweet: "created_at": "Wed Oct 19 random-chars 2016" image: "created_at": "Wed Oct 19 whatever 2016"

Если вы хотите исключить тот или иной, удалите соответствующая часть из сценария, например, для получения только твита ...

for f in **; do [[ -f "$f" ]] && echo -e ""$f":\n tweet: $(sed -nr '/}/N; s/.*}.*\n(.*"Wed Oct 19 .* 2016)/\1/Ip' "$f")" done

Примечания

sed -n должны быть тихими, пока мы не попросим выход - это используется в сочетании с команда печати p для имитации действия grep -r использует расширенное регулярное выражение /}/N, найдите строку с } и прочитайте следующую строку в пространстве шаблонов [f 24] найдите строку без } и прочитайте следующую строку в пространстве шаблонов I регистр без учета регистра p распечатайте найденные / отредактированные строки s/old/new замените old на new
2
ответ дан 24 July 2018 в 18:31

Другие вопросы по тегам:

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