Отфильтруйте текст из каждого файла и превратите его в список значений, разделенных запятыми

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

#!/bin/bash for file in folder/*.txt do grep 'sometext:' $file | sed '/^.*:\s*//' >> list.txt #doing simliar stuff with other lines in the current file done 

Я попытался использовать echo -n для разметки новой строки, но это ничего не принесло.

Что должен делать код:
Для каждого файла в папке найдите строки, начинающиеся с некоторых шаблонов (например, sometext: someothertext: etc) и добавьте оставшуюся часть строки и a в одну строку, соответствующую этому файлу в list.txt .

Пример содержимого файла в папке:

 randomtext: ... sometext: Hello randomtext: ... someothertext: World somedifferenttext: ! randomtext: 

Результатом будет одна строка в выходном файле Hello,World,!,

2 Solutions collect form web for “Отфильтруйте текст из каждого файла и превратите его в список значений, разделенных запятыми”

ОК, прежде всего, не используйте цикл for ! Это очень неэффективно. Просто дайте grep все имена файлов сразу:

 grep 'sometext:' folder/*.txt 

В этом случае, однако, я бы использовал awk вместо grep . Я попробовал 10 экземпляров вашего входного файла:

 $ awk '{ if($1~/sometext|someothertext|somedifferenttext/){ printf "%s,",$2 } if(FNR==1 && NR>1){ print "" } } END{ print "" }' folder/*txt Hello,World,!, Hello,World,!, Hello,World,!, Hello,World,!, Hello,World,!, Hello,World,!, Hello,World,!, Hello,World,!, Hello,World,!, Hello,World,!, Hello,World,!, 

объяснение

awk – это язык сценариев, который читает его ввод строки за строкой и разбивает каждую строку на пробелы (по умолчанию вы можете изменить это с -F ) в поля. Первое поле будет $1 , второе $2 и т. Д.

  • if($1~/sometext|someothertext|somedifferenttext/){ : если первое поле соответствует sometext или someothertext или someothertext . Обратите внимание, что это также будет соответствовать foosometext . Если вы хотите ограничить точное совпадение, измените это на:

     if($1=="sometext:" || $1=="someothertext:" || $1=="somedifferenttext:"){ 
  • printf "%s,",$2 : если выполняется условие выше, напечатайте второе поле, за которым следует запятая.

  • if(FNR==1 && NR>1){ print "" } : NR – это текущий номер строки ввода, а FNR – номер строки текущего файла. Итак, напечатайте новую строку (вызов print awk по умолчанию добавляет новую строку, поэтому ничего не печатать, как печать новой строки) каждый раз, когда номер строки файла равен 1, но не если общее число обработанных строк также одно. Другими словами, печатайте новую строку каждый раз, когда мы начинаем читать новый файл.

  • END{ print "" }' : также распечатать новую строку после обработки всех файлов.

Обратите внимание, что это предполагает, что у вас есть только 2 поля в строке. Если вам нужно распечатать всю строку вместо этого, вы можете использовать (используя версию, которая выводит только точные соответствия для иллюстрации):

 awk '{ if($1=="sometext:" || $1=="someothertext:" || $1=="somedifferenttext:"){ $1=""; printf "%s,",$0 } if(FNR==1 && NR>1){print ""} }END{print ""}' folder/*txt | sed 's/^ //' 

Разница в том, что мы используем $0 (полная строка) вместо $2 и устанавливаем $1 в пустую строку перед печатью. Это приводит к дополнительному пространству, напечатанному в начале (поскольку пустой $1 по-прежнему считается полем), поэтому мы передаем это через sed чтобы удалить его.


Кроме того, вы также можете сделать все это в Perl:

  $ perl -lane ' if($F[0]=~/(sometext|someothertext|somedifferenttext):/){ push @k,@F[1..$#F] } if(eof){ print join ",", @k; @k=(); }' folder/file* Hello,World,! Hello,World,! Hello,World,! Hello,World,! Hello,World,! Hello,World,! Hello,World,! Hello,World,! Hello,World,! Hello,World,! Hello,World,! 

Или, чтобы также иметь трейлинг,:

  $ perl -lane ' if($F[0]=~/^(sometext|someothertext|somedifferenttext):$/){ push @k,@F[1..$#F] } if(eof){ print join ",", @k , ""; @k=(); }' folder/file* Hello,World,!, Hello,World,!, Hello,World,!, Hello,World,!, Hello,World,!, Hello,World,!, Hello,World,!, Hello,World,!, Hello,World,!, Hello,World,!, Hello,World,!, 

объяснение

Основная идея здесь та же. Переключатель -a Perl ведет себя как awk , разбивая каждую строку ввода на массив @F . Затем, если 1-й элемент массива является одной из нужных строк, остальные поля ( @F[1..$#F] ) добавляются в массив @k . Если мы дойдем до конца файла ( if(eof) ), мы присоединяем содержимое массива @k с запятыми и печатаем полученную строку.


Наконец, вот один из способов сделать это так, как вы пытались (предположив GNU grep ):

 $ for f in folder/*; do grep -hoP '^(sometext|someothertext|somedifferenttext): \K.*' "$f" | perl -pe 's/\n/,/; END{print "\n"}'; done Hello,World,!, Hello,World,!, Hello,World,!, Hello,World,!, Hello,World,!, Hello,World,!, Hello,World,!, Hello,World,!, Hello,World,!, Hello,World,!, Hello,World,!, 

С gnu sed :

 sed -Es '/pattern1|pattern2|pattern3/{ s/.*:[[:blank:]]*//;H} $!d;x;/^\n$/d;s/\n(.*)/\1,/;s/\n/,/g' folder/*.txt > list.txt 

где list.txt будет выглядеть примерно так:

 file1match1,file1match2, file2match1, file4match1,file4match2,file4match3, 

поэтому file3 отсутствует на выходе, так как не было шаблона соответствия строк * .
Как это работает: он обрабатывает каждый файл – отдельно, удаляя (через s/.*:[[:blank:]]*// ) ненужную часть в строках, которые соответствуют шаблону * и добавляет результат в старый буфер H Он удаляет каждую строку, кроме la $ t, когда e x изменяет буферы. Если в пространстве шаблонов есть только \n ewline, это означает, что в этом шаблоне не указан символ *, поэтому он удаляет пространство шаблонов. Кроме того, он удаляет ведущую \n строку, заменяет остальные запятыми и добавляет конечную запятую.

С другими sed вам придется петли:

 for file in folder/*.txt do sed '/pattern1\|pattern2\|pattern3/{ s/.*:[[:blank:]]*// H } $!d x /^\n$/d s/\n\(.*\)/\1,/ s/\n/,/g' "$file" done > list.txt 
  • Как grep для 2 строк (условие AND) внутри блока, которые не находятся в одной строке, а затем найти что-то еще в этом же блоке
  • Эффективно экономить пару каждой строки с линиями другого файла
  • Как распечатать все, кроме Nth, до последней строки в sed?
  • Как распечатать все строки, не содержащие строку вместе со смежными строками?
  • Как я могу удвоить символы новой строки в потоке вывода
  • Могу ли я создать специальный файл в linux, который на самом деле является результатом сценария?
  • Добавить строку в начало второй строки, используя unix
  • Как определить строки в файлах на определенной длине
  • Фильтр Требовать капитальные слова из файла (не все заглавные слова)
  • удаляя каждый. после] появляются в строке в полном текстовом файле
  • как извлечь определенные столбцы
  • Linux и Unix - лучшая ОС в мире.