Как использовать grep, чтобы проверить, существует ли строка шаблона, и записать ее в другой файл?

У меня есть файл журнала с таким содержимым

The color is Orange then can used to binding.
The color is Black then can used to binding.
The animal Lion need to carefully. 
The color is Black then can used to binding.
The animal Zebra need to carefully. 
The animal Tiger need to carefully.
The animal Bee need to skip.
The color is White then can used to binding.
The color is Yellow then can used to binding.
The animal Ant need to skip.
The animal Tiger need to carefully. 
The color is Red then can used to filled.
The color is Green then can used to filled.

Я хочу проверить, содержит ли строка шаблон и не существует ли она, а затем записать в другой журнал.

#!/bin/bash
source_file = "/home/user1/source/source_sample.log"
dest_file = "/home/user1/dest/dest_sample.log

#define line with pattern
pattern1 = ".*then can used to binding"
pattern2 = ".*need to carefully"

#check if line of pattern exist or not in destination file, if not then write it
grep -e "$pattern1" -e "$pattern2" $source_file >> $dest_file

Ожидаемый результат в dest_sample.log будет таким. Если строка шаблона не существует в файле назначения, запишите ее. Если он уже существует, не пишите его.

The color is Orange then can used to binding.
The color is Black then can used to binding.
The animal Lion need to carefully. 
The animal Zebra need to carefully. 
The animal Tiger need to carefully.
The color is White then can used to binding.
The color is Yellow then can used to binding.

🤔 А знаете ли вы, что...
Bash поддерживает множество операторов для выполнения арифметических операций.


89
4

Ответы:

Простая команда egrep выполнит фильтрацию, sort -u можно использовать для устранения дубликатов в выводе.

$ egrep '(then can used to binding|need to carefully)' input.txt | sort -u
The animal Lion need to carefully.
The animal Tiger need to carefully.
The animal Tiger need to carefully.
The animal Zebra need to carefully.
The color is Black then can used to binding.
The color is Orange then can used to binding.
The color is White then can used to binding.
The color is Yellow then can used to binding.

awk на помощь!

$ awk '/then can used to binding|need to carefully/ && ($1=$1) && !a[$0]++' file

The color is Orange then can used to binding.
The color is Black then can used to binding.
The animal Lion need to carefully.
The animal Zebra need to carefully.
The animal Tiger need to carefully.
The color is White then can used to binding.
The color is Yellow then can used to binding.

фильтровать только совпадающие строки, нормализовать поля (избавиться от лишних пробелов) и фильтровать только уникальные записи.


Если файлы журналов не помещаются в памяти, вас заботит порядок строк и не заботят конечные пробелы:

(
    awk '
        /then can be used to binding|need to carefully/ { 
            sub(/[[:space:]]+$/,"")
            print NR FS $0
        }
    ' source.log | sort -k2 -u ;

    awk '
        /then can be used to binding|need to carefully/ { 
            sub(/[[:space:]]+$/,"")
            print NR FS $0 RS NR FS $0
        }
    ' destination.log
) |
sort -k2 |
uniq -f1 -u |
sort -n |
sed 's/^[0-9]* //' > new.log

cat new.log >> destination.log
  • сначала awk находит в исходном коде строки, соответствующие регулярному выражению, обрезает конечные пробелы и печатает с префиксом по номеру строки; его вывод затем дедуплицируется с помощью sort, игнорируя номера строк (поле 1)
  • второй awk повторяет фильтрацию для пункта назначения, но печатает каждую строку дважды
  • выходные данные обоих awk объединяются и повторно sort
  • затем uniq отбрасывает дубликаты, также игнорируя номера строк
    • поскольку каждая строка, находящаяся в пункте назначения, появляется как минимум дважды, все строки, уже находящиеся в пункте назначения, отбрасываются.
  • третий sort восстанавливает исходный порядок файлов.
  • затем sed удаляет номер строки
  • наконец, любые новые результаты добавляются к месту назначения.

Если файлы журналов небольшие, подход @karafka можно изменить:

awk '
    !/then can be used to binding|need to carefully/ { next }
    { sub(/[[:space:]]+$/,"") }
    !seen[$0]++ && NR>FNR
' destination.log source.log >new.log

cat new.log >>destination.log
  • отфильтровать строки, которые не соответствуют регулярному выражению

  • обрезать конечные пробелы

  • сохранить эту строку, которую видели

  • при первом появлении строки, если она пришла из нового ввода, распечатайте ее

  • добавить новые результаты в пункт назначения


Решено

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

Во-первых, в ваших данных есть строки, которые выглядят одинаково, но это не так; у некоторых есть пробелы в конце, а у других нет.

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

Вы спрашивали, как это сделать с помощью grep:

grep -Fxvf $dest_file $source_file | # Fixed string search 
  grep -E 'then can used to binding|need to carefully' >> $dest_file

Требуется два прохода.

Сначала выполняется сканирование -Fфиксированной строки -x(точное совпадение) -v(исключение) $source_file с использованием строк $dest_file в качестве -fфайла совпадающих строк. Это дает нам только строки из $source_file НЕ в $dest_file уже.

Направьте это на grep -E 'then can used to binding|need to carefully' (или grep -e "$pattern1" -e "$pattern2"), чтобы выбрать нужные строки из вывода первого grep и добавить к $dest_file.

Если возможно, что в $source_file могут быть повторяющиеся новые строки, вы можете удалить дубликаты перед их добавлением в $dest_file:

grep -Fxvf $dest_file $source_file | # Fixed string search 
  grep -E 'then can used to binding|need to carefully' |
  sort -u >> $dest_file

Это изменит ваш порядок, если только $source_file не имеет порядка, который вы можете воспроизвести, но вы сказали, что порядок не имеет значения.

Лучший способ

То, что вы просили, было способом использования grep, но awk можно сделать это за один процесс, за один проход (каждый файл), без переупорядочения ваших данных.

awk 'NR==FNR{seen[$0]=1;next} 1==seen[$0]{next} 
  /then can used to binding|need to carefully/{seen[$0]=1;print}
' $dest_file $source_file >> $dest_file