Как избежать появления новых строк с grep-o для нескольких совпадений в одной строке (на тексте из нескольких строк)
У меня есть следующий текст::
aaa rr tt zz pp
aaa pp xx yy uu zz
И нужно извлечь все' aaa',' zz 'и' xx ' шаблон и распечатать их на одной строке, как это:
aaa zz
aaa xx zz
Лучшее, что я нашел, это grep -oP 'aaa|xx|zz'
, но это возвращает каждый шаблон, найденный на новой строке:
aaa
zz
aaa
xx
zz
Я попытался добавить что-то вроде tr -d '\n'
, но в этом случае он возвращает все матчи на одной строке, что не то, что я хочу.
NB: мне нужно решение, которое поддерживает регулярное выражение с ненасытным регулярным выражением, поскольку шаблоны поиска будут выглядеть следующим образом:^.+?,|,IN:.+?\-|,OUT:.+?-|State.+?[$,]
Ответы - Как избежать появления новых строк с grep-o для нескольких совпадений в одной строке (на тексте из нескольких строк) / How to avoid having newlines with grep -o for multiple match at the same line (on a text of several lines)

29.01.2020 12:35:25
Предполагая , что у вас есть grep -P
, вот простой постпроцессор Awk, чтобы перестроить выходные данные в нужный формат.
grep -Pno '^.+?,|,IN:.+?\-|,OUT:.+?-|State.+?[$,]' - /dev/null <file |
awk 'BEGIN { re="^\\(standard input\\):[1-9][0-9]*:" }
$0 ~ re { sep="\n"; sub(re, "") }
{ if(NR>1) printf "%s", sep; printf "%s", $0; sep=" " }
END { if(sep) printf "\n" }'
Если результаты grep
могут случайно вывести префикс, который выглядит как (standard input):1:
из фактического соответствия, это не будет работать.
Это из BSD grep
; если ваш локальный grep
выводит префикс имени файла другого формата для стандартного ввода (или если вам нужно выполнить рефакторинг для чтения ряда именованных файлов вместо стандартного ввода), регулярное выражение Awk необходимо будет соответствующим образом адаптировать.


29.01.2020 12:45:18
Вы можете использовать
while IFS= read -r line; do
echo $(grep -oP 'aaa|xx|zz' <<< "$line");
done < file
То есть,
- Читать входной файл строка за строкой
- Получите ваши совпадения с командой
grep
не заключен в двойные кавычки.
Если у вас есть определенные пробелы внутри совпадений, которые вы хотите сохранить, рассмотрите возможность использования
$(...)
Таким образом, вы получите совпадения по строке через пробел. Вы можете использовать любой пользовательский разделитель в команде while IFS= read -r line; do
echo "$(grep -oP 'aaa|xx|zz' <<< "$line" | awk '{ printf "%s", $0" "}')";
done < file
(после awk
).

echo
, или наоборот.


while IFS= read -r line; do echo $(grep -oP 'aaa|xx|zz' <<<"$line"); done <<$'aaa bb cc\nzz xx yy\nboo baa

echo "$(grep -oP 'aaa|xx|zz' | awk '{ printf "%s", $0 }')"
будет работать и правильно цитировать выходные данные из оболочки. Это лучший подход, если выходные grep
могут содержать нерегулярные пробелы и / или подстановочные знаки без кавычек. Смотрите также stackoverflow.com/questions/10067266/…



^.+?,|,IN:.+?\-|,OUT:.+?-|State.+?[$,]
очень неэффективно, и я боюсь ошибиться. Что вы хотите сопоставить с [$,]
? Вы понимаете, что он соответствует $
или ,
вам нужно ,
. Кроме того , нет необходимости использовать ^[^,]*,|,IN:[^-]*-|,OUT:[^-]*|State[^,]*,
, использовать P
с этим шаблоном, так как больше нет специальных конструкций PCRE. Если вводимый текст длинный, ленивый точечный узор может быть действительно опасным узором.
