Как разобрать поля из разных строк, чтобы создать новую запись со всеми этими полями
У меня есть файл с этой структурой:
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, я не знаю почему.
Еще раз всем спасибо за ваше время.
Патрисио.