извлечение строк текста из длинного файла

извлечение строк текста из длинного файла

У меня есть следующий текстовый файл:

#unimportant comment
#possible more unimportant comments
#info1 info2 info3 ,importantname1
importanttext1
#info1 info2 info3 ,importantname2
importanttext2
#info1 info2 info3 ,importantname3
importanttext3

Я хочу разбить каждый файл на отдельные файлы. Все, что мне действительно нужно, это извлечь не прокомментированные URL-адреса, сохранение комментариев необязательно. Я хочу, чтобы каждый файл был назван, например, importantname1.txt или именем, следующим за запятой в конце каждой строки комментария, с добавлением .txt

поэтому importantname1.txt будет иметь следующее содержимое:

importanttext1 

или возможно

#info1 info2 info3 ,importantname1
importanttext1

поэтому строка будет извлечена и сохранена с именем файла после комментария и добавлена ​​с расширением .txt, в данном случае filename importantname1.txt

Мне нужно сделать это для каждого набора строк в файле примера. Сохранение комментариев неважно, но мне нужно, чтобы это можно было использовать в скриптах. Мне также нужно учесть неизвестное количество строк комментариев в заголовке. Строка комментария всегда будет перед каждой строкой importanttextX

решение1

Пытаться:

awk -F, '/^#/{f=$NF".txt";cmt=$0; next} {printf "%s\n%s\n",cmt,$0 >f; close(f)}' file

Пример

Применительно к вашему образцу входных данных:

$ awk -F, '/^#/{f=$NF".txt";cmt=$0; next} {printf "%s\n%s\n",cmt,$0 >f; close(f)}' file

После выполнения вышеуказанного в каталоге появятся следующие файлы:

$ ls
file  importantname1.txt  importantname2.txt  importantname3.txt

Содержимое новых файлов:

$ cat importantname1.txt 
#info1 info2 info3 ,importantname1
importanttext1
$ cat importantname2.txt 
#info1 info2 info3 ,importantname2
importanttext2
$ cat importantname3.txt 
#info1 info2 info3 ,importantname3
importanttext3

Как это работает

Awk читает входной файл построчно. Наш скрипт классифицирует эти строки как комментарии или не-комментарии. Для строк комментариев имя файла и комментарий сохраняются. Для не-комментариев создается новый файл и печатается

  • `-Ф,

    Это говорит awk использовать запятую в качестве разделителя полей при вводе. Таким образом, имя файла всегда будет последним полем.

  • /^#/{f=$NF".txt";cmt=$0; next}

    Если строка начинается с #, мы сохраняем последнее поле, $NF, плюс .txtкак имя файла f. Вся строка комментария сохраняется как cmt. Затем мы говорим awk пропустить оставшиеся команды и перейти к началу строки заново next.

  • printf "%s\n%s\n",cmt,$0 >f; close(f)

    Для строк, не являющихся комментариями, мы печатаем последний просмотренный комментарий, cmt, и текущую строку, $0, в имя файла последнего просмотра f. Затем мы закрываем дескриптор файла для f.

Защита от плохих имен файлов

Если поля, которые должны использоваться в качестве имен файлов, содержат /, ОС будет интерпретировать имена файлов как включающие каталоги. Чтобы избежать этого, мы можем заменить все /на -using gsub(/\//, "-", f)следующим образом:

awk -F, '/^#/{f=$NF".txt";gsub(/\//, "-", f); cmt=$0; next} {printf "%s\n%s\n",cmt,$0 >f; close(f)}' file

решение2

Комбинация grepи csplitможет выполнить эту работу, путем а) grep​​пинга всех не прокомментированных строк плюс предыдущей информационной строки и б) разделения вывода на основе информационной строки комментария:

grep -v -B1 '^#' file | csplit -z - '/^#/' '{*}'

Т.е. не -vизвлекать строки, которые имеют # в начале, ^#а одну строку, предшествующую таким строкам -B1. Затем разделить входящий конвейерный ввод -по каждому # в начале строки, игнорировать пустые файлы -zи делать это как можно чаще {*}.

Переименование должно быть отдельным шагом ( csplitавтоматически присваивает выходному отверстию имена xx00, xx01 ... - измените префикс и суффикс с помощью опций -fи -bсоответственно)

#/bin/bash
for f in xx* ; do
   mv "$f" "$( sed -n '2p' "$f" )".txt
done

Связанный контент