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

У меня есть файл с этой структурой:

http://paste.ubuntu.com/21136265/

И мне нужно захватить все данные из строки "ADSTART ACTION(ADD)" на следующую строку с тем же текстом, чтобы создать одну запись или строку.

Извините, но я не могу опубликовать пример вывода, потому что все данные между строками 'ADSTART' в одной строке или записи, я работаю в z/OS, и у нас есть понятие длины записи.

Я пытаюсь сделать это в REXX для z/OS и в AWK в UNIX SYSTEM SERVICES для z/OS, но я застрял, помещая все поля в строку, и я не могу понять, как это сделать.

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

Любая идея будет оценена.

Спасибо заранее.

Патрисио.

5 ответов

Если вы используете REXX, то почему бы вам просто не воспользоваться инструкцией разбора для очистки файла отчета? Инструкция Parse использует шаблон шаблона, который очень прост, но эффективен.

Вот пример:

/* REXX */

queue "ADSTART  ACTION(ADD)"
queue "  ADID(ABCD0B          ) ADVALFROM(111230) CALENDAR(CALSEM7J        )"
queue "  DESCR('DESCRIPTION  ')"
queue "  ADTYPE(A)"
queue "  GROUP(PBQOPC  )"
queue "  OWNER('OWNER1')"
queue "  PRIORITY( 5) ADSTAT(A)"
queue "  ODESCR('ALADIN                  ')"
queue "ADRUN ACTION(ADD)"
queue "  PERIOD(HEB     )  RULE(3) VALFROM(091230)  VALTO(711231)"
queue "  SHIFT(   0)             SHSIGN(F)"
queue "  DESCR('DESCRIPTION')"
queue "  TYPE(N)"
queue "    IADAYS(  1,  2,  3,  4,  5,  6,  7)"
queue "  IATIME(1700) DLDAY(   1)   DLTIME(0600)"

do while queued() > 0
  parse pull rec
  select
    when startswith(rec,"ADSTART") then do
      p. = '' /* the output record */
      parse var rec with . 'ACTION('p.action')'
      do queued()
        parse pull rec
        if left(rec,1) /= ' ' then do
          /* End of parameter group. Re-queue the record and break */
          push rec
          leave
        end
        select
          when startswith(rec, "  ADID") then do
            parse var rec with . "ADID("p.adid") ADVALFROM("p.advalfrom")" ,
              "CALENDAR("p.calendar")"
          end
          when startswith(rec, "  DESCR") then do
            parse var rec with "DESCR('"p.desc"')"
          end
          when startswith(rec, "  PRI") then do
            parse var rec with "PRIORITY("p.priority") ASTAT("p.adstat")"
          end
          otherwise nop
        end
      end
      /* write out the record in 1 line */
      say strip(p.action) strip(p.adid) strip(p.advalfrom) strip(p.calendar),
          strip(p.desc) strip(p.priority) strip(p.adstat)
    end
    when startswith(rec,"ADRUN") then do
      /* do some stuff to parse this */
    end
    otherwise nop
  end
end

exit 0

startswith:
  parse arg input, prefix
  input_len = length(input)
  if input_len = 0 then return 0
  prefix_len = length(prefix)
  if prefix_len = 0 then return 0
  return input_len >= prefix_len & left(input,prefix_len) = prefix

Если вы чувствуете себя комфортно в среде z/OS UNIX, если вам нужно что-то более мощное, чем REXX и / или AWK, вам следует воспользоваться моим портом z / OS Lua. Он поставляется с пакетом LPeg, который позволяет легко писать лексеры и парсеры с очень небольшим количеством строк кода.

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

/* REXX */                                                                   

queue "ADSTART  ACTION(ADD)"                                                 
queue "  ADID(ABCD0B          ) ADVALFROM(111230) CALENDAR(CALSEM7J        )"
queue "  DESCR('DESCRIPTION  ')"                                             
queue "  ADTYPE(A)"                                                          
queue "  GROUP(PBQOPC  )"                                                    
queue "  OWNER('OWNER1')"                                                    
queue "  PRIORITY( 5) ADSTAT(A)"                                             
queue "  ODESCR('ALADIN                  ')"                                 
queue "ADRUN ACTION(ADD)"                                                    
queue "  PERIOD(HEB     )  RULE(3) VALFROM(091230)  VALTO(711231)"           
queue "  SHIFT(   0)             SHSIGN(F)"                                  
queue "  DESCR('DESCRIPTION')"                                               
queue "  TYPE(N)"                                                            
queue "    IADAYS(  1,  2,  3,  4,  5,  6,  7)"                              
queue "  IATIME(1700) DLDAY(   1)   DLTIME(0600)"                            

do while queued() > 0                                                        
  parse pull rec                                                             
  if left(rec,1) /= ' ' then do                                              
    line = rec                                                               
    do queued()                                                              
      parse pull rec                                                         
      if left(rec,1) /= ' ' then do                                          
        push rec;leave                                                                
      end                                                                    
      line = line rec                                                        
    end                                                                      
    say space(line,1) 
  end                                                                        
end                                                                          

exit 0     

Возможно это сделало бы это:

awk '/ADSTART  ACTION\(ADD\)/{print buf; buf=""} {buf=buf""$0" "} END{print buf}' test.in

Комментируемая версия:

/ADSTART  ACTION\(ADD\)/ { # for records where ADSTART occurs
  print buf                # output the buffer variable
  buf=""                   # then empty the buffer
} 
{                          # for all records
  # gsub(/^ +| +$/,"")     # here you could trim leading and trailing space
  buf=buf""$0" "           # build the buffer 
} 
END {                      # in the end
  print buf                # output the remaining buffer
}

Хотя приведенное выше решение может работать не для нескольких строк на блок, решение, которое печатает только текст между ADSTART ACTION (ADD) и предполагает, что будет напечатан только один блок

Bash:

gawk 'BEGIN {s = 0} /ADSTART.*ACTION(ADD)/ {s = (s + 1)% 2} (s == 1) {print}' | sed ': a; N; $! ba; s / \ n // g'

(ADSTART... строки опущены)

Попробуй это;

sed -n '/ADSTART  ACTION(ADD)/,/ADRUN/p'  <filename> | sed 's/ADRUN ACTION(ADD)//g'

Большое спасибо за все ответы.

В конце концов это было довольно легко, потому что, когда я делаю FTP из z/OS в USS (Unix System Services для z/OS) в двоичном формате, все данные находятся в одной строке.

Сначала я работал с файлом, переданным через FTP (ASCII xlate) на мой компьютер, а затем передавался в USS в двоичном FTP с WinSCP.

Этот код я использовал для замены текстового шаблона на возврат каретки:

    sed 's/ADSTART  ACTION(ADD)/\
    /g' <input file> ><output file>

возврат каретки вставлен нажатием клавиши ввода, потому что /r /'$'' /n /x0D не работает в USS, я не знаю почему.

Еще раз всем спасибо за ваше время.

Патрисио.

Другие вопросы по тегам