Селективное извлечение данных

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

Informatica(r) PMCMD, version [9.5.1 HotFix4], build [313.0217], SOLARIS 64-bit Copyright (c) Informatica Corporation 1994 - 2014 All Rights Reserved. Invoked at Wed Dec 30 11:13:42 2015 Connected to Integration Service: [TEST_Integration_Service]. Integration Service status: [Running] Integration Service startup time: [Sun Dec 27 06:37:32 2015] Integration Service current time: [Wed Dec 30 11:13:42 2015] Folder: [ALS_DIM] Workflow: [wf_ld_als_dim] version [1]. Workflow run status: [Scheduled] Workflow run error code: [0] Workflow run id [0]. Schedule time: [Wed Dec 30 19:00:00 2015] Workflow run type: [Schedule] Run workflow as user: [Administrator] Run workflow with Impersonated OSProfile in domain: [] Integration Service: [TEST_Integration_Service] Folder: [ALS_FACT] Workflow: [wf_s_m_ld_interchanges_detail_log] version [1]. Workflow run status: [Scheduled] Workflow run error code: [0] Workflow run id [0]. Schedule time: [Mon Jan 04 16:30:00 2016] Workflow run type: [Schedule] Run workflow as user: [Administrator] Run workflow with Impersonated OSProfile in domain: [] Integration Service: [TEST_Integration_Service] Folder: [ALS_PRD] Workflow: [wf_maint_service_fields] version [1]. Workflow run status: [Scheduled] Workflow run error code: [0] Workflow run id [0]. Schedule time: [Thu Dec 31 07:10:00 2015] Workflow run type: [Schedule] Run workflow as user: [Administrator] Run workflow with Impersonated OSProfile in domain: [] Integration Service: [TEST_Integration_Service] Number of scheduled workflows on this Integration Service: [3] Disconnecting from Integration Service 

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

Например:

 Insert into <tablename> values('ALS_DIM', 'wf_ld_als_dim', 'Scheduled', 'Wed Dec 30 19:00:00 2015', 'TEST_Integration_Service') 

Это нужно извлечь для первого набора и так далее.

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

У меня есть очень предварительные знания о сценариях оболочки, поэтому было бы здорово помочь вам в этом.

Подход Perl:

 $ perl -lne 'if(/^(Folder|Workflow|Workflow.*?status|Sched.*time|Integration Service):.*?\[([^][]+)/){++$k%5==0 ? print "$2" : printf "%s,",$2}' file ALS_DIM, wf_ld_als_dim, Scheduled, Wed Dec 30 19:00:00 2015, TEST_Integration_Service ALS_FACT, wf_s_m_ld_interchanges_detail_log, Scheduled, Mon Jan 04 16:30:00 2016, TEST_Integration_Service ALS_PRD, wf_maint_service_fields, Scheduled, Thu Dec 31 07:10:00 2015, TEST_Integration_Service 

Или, менее сконденсированный:

 $ perl -lne ' if(/^ ## Match the beginning of the line ( ## 1st capturing group: $1 Folder | ## The various things we want to match Workflow | Workflow.*?status | Sched.*time | Integration\s*Service ): ## Only if they are followed by a : .*?\[ ( ## 2nd caprturing group: $2. [^][]+ ## The longest string of non-] or [ )/x ## The x allows writing multiline regexes ) { ## If this line matches... $k=$k+1; ## Increment the counter $k by one if($k%5==0){ ## If the current value of $k is a multiple of 5. print "$2" ## Print the 2nd captured group and a newline. } ## The newline is automatically added by the -l. else{ printf "%s,",$2 ## For other lines, just print with no newline. } }' file ALS_DIM, wf_ld_als_dim, Scheduled, Wed Dec 30 19:00:00 2015, TEST_Integration_Service ALS_FACT, wf_s_m_ld_interchanges_detail_log, Scheduled, Mon Jan 04 16:30:00 2016, TEST_Integration_Service ALS_PRD, wf_maint_service_fields, Scheduled, Thu Dec 31 07:10:00 2015, TEST_Integration_Service 

Чтобы добавить Insert ... , вы можете просто передать его через простое sed :

 $ perl -lne 'if(/^(Folder|Workflow|Workflow.*?status|Sched.*time|Integration Service):.*?\[([^][]+)/){++$k%5==0 ? print "$2" : printf "%s,",$2}' file | sed "s/^/Insert into <tablename> values('/; s/,/','/g; s/$/')/" Insert into <tablename> values("ALS_DIM","wf_ld_als_dim","Scheduled","Wed Dec 30 19:00:00 2015","TEST_Integration_Service") Insert into <tablename> values("ALS_FACT","wf_s_m_ld_interchanges_detail_log","Scheduled","Mon Jan 04 16:30:00 2016","TEST_Integration_Service") Insert into <tablename> values("ALS_PRD","wf_maint_service_fields","Scheduled","Thu Dec 31 07:10:00 2015","TEST_Integration_Service") 

Команда sed запускает три оператора замещения:

  • s/^/Insert into <tablename> values("/ : ^ – начало строки. Итак, s/^/foo/ просто вставляет foo в начало строки. Здесь он вставляет nsert into <tablename> values(" .
  • s/,/','/g : заменить все ( s///g ) запятыми на ',' .
  • s/$/")/' : $ – конец строки, поэтому это добавит )" в конце.

Решение sed

 sed -ne'/^Folder: *\[/!{' \ -e'/^Workflow\( run status\)\{0,1\}: *\[/!{' \ -e'/^Schedule time: *\[/!{' \ -e'/^Integration Service: *\[/!d' \ -e\} -e\} -e\} -e"s//'/" -e"s/\].*/'/" -e'H;x' \ -e'/ .*\n.*/h' -e's///' -e'x' \ -e's//Insert into <tablename> values(&)/' \ -e's/\n//' -e's//, /gp' 

 Insert into <tablename> values('ALS_DIM', 'wf_ld_als_dim', 'Scheduled', 'Wed Dec 30 19:00:00 2015', 'TEST_Integration_Service') Insert into <tablename> values('ALS_FACT', 'wf_s_m_ld_interchanges_detail_log', 'Scheduled', 'Mon Jan 04 16:30:00 2016', 'TEST_Integration_Service') Insert into <tablename> values('ALS_PRD', 'wf_maint_service_fields', 'Scheduled', 'Thu Dec 31 07:10:00 2015', 'TEST_Integration_Service') 

Таким образом, первые строки отрицают приемлемые совпадения, такие как …

 if ! match ^Folder: *\[ then if ! match ^Workflow: *\[ or ^Workflow run status: *\[ then if ! match ^Schedule time: *\[ then if ! match ^Integration Service: *\[ then delete fi fi fi fi 

Как только линия действительно соответствует любому в цепочке, цепь разрушается и не пересекается до конца. Это означает, что последнее регулярное выражение, проверенное для любой заданной совпадающей строки, будет описывать главу строки до правой квадратной скобки. В сценарии sed вы можете снова ссылаться на самое последнее скомпилированное регулярное выражение с // пустым адресом. И я просто s//'/ убираю его и заменяю его главной цитатой в желаемом выводе.

Остается только вся информация, которую вы хотите, плюс плюс конечный контекст, следующий за первой ] в каждой строке. И поэтому я s/\].*/'/ …………………………………

В этот момент все линии были разделены только на части, которые вы хотите, но они еще не объединены. Для этого я использую старое пространство H которое сохраняется в цикле линии. И добавьте копию каждой строки в старое пространство H , e x измените буферы удержания и шаблона и ищите / .*\n.*/ Для <space>, а затем <newline> – которая происходит только на следующая удерживаемая строка после строки даты.

Если шаблон найден, я перезаписываю его старым пространством и s/// удаляет все пространство шаблонов (чтобы оставить его пустым для следующей итерации, потому что это последняя строка для этого) . Пустой адрес s/// здесь удаляет только содержимое строки, которая соответствует шаблону <space> + <newline>, и поэтому только в последней строке каждой итерации может быть выполнена любая из этих инструкций.

Независимо от того, я после этого изменил буферы удержания и шаблона в последний раз, и поэтому буфер шаблонов либо теперь будет содержать все совпадения этой итерации, разделенные символами <newline> , либо он будет содержать только самое последнее совпадение и нуль < newline> . Буфер удержания в этой точке либо пуст, если это последняя соответствующая строка для этой итерации, либо она содержит все соответствующие строки до этой точки, каждая из которых имеет префикс ведущей <новой строки> .

Затем я снова ссылаюсь на одно и то же регулярное выражение и пытаюсь заменить все пространство шаблонов, которое соответствует шаблону <space> + <newline> для себя, заключенного в значения Insert into <tablename> values( и завершающего ) .

И последнее, если они есть, я s/// ubstitute ни для чего не является ведущей <новой строкой> в пространстве шаблонов последней сопоставимой строки, а все остальные <новые строки> для запятой, а затем <space> . Если эта функция s/// ubstitution успешна, ее результаты передаются в stdout.