У меня есть команда, которую я смог собрать с помощью сообщества Stackoverflow. Теперь у меня есть небольшая проблема со сценарием, это очень небольшая проблема, но она меня беспокоит.
Ниже приведен сценарий, который я использую:
#!/bin/bash
read -p "Enter /DIR/PATH/FILENAME where you wish to copy the data: " FILENAME
echo "Enter the JOB_NAME or %SEARCHSTRING%"
while read -r i;
do
awk '
BEGIN {
print "\"insert_job\",\"job_type\",\"box_name\",\"command\",\"machine\",\"owner\",\"date_conditions\",\"condition\",\"run_calendar\",\"exclude_calendar\",\"days_of_week\",\"run_window\",\"start_times\",\"start_mins\",\"resources\",\"profile\",\"term_run_time\",\"watch_file\",\"watch_interval\"" }
/job_type/ {
if (NR>1){printf "%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s\n", jn, jt, box, cmd, mcn, own, dc, c, rc, ec, dow, ruw, st, sm, res, prof, trt, wf, wi} jn = "\""$2"\""; jt = "\""$4"\""; box = "\" \""; cmd = "\" \""; mcn = "\" \""; own = "\" \""; dc = "\" \""; c = "\" \""; rc = "\" \""; ec = "\" \""; dow = "\" \""; ruw = "\" \""; st = "\" \""; sm = "\" \""; res = "\" \""; prof = "\" \""; trt = "\" \""; wf = "\" \""; wi = "\" \""}
/box_name/ {box = "\""$2"\""}
/command/ {$0=substr($0,index($0,$2)); cmd = "\""$0"\""}
/machine/ {mcn = "\""$2"\""}
/owner/ {own = "\""$2"\""}
/date_conditions/ {dc = "\""$2"\""}
/condition/ {$0=substr($0,index($0,$2)); c = "\""$0"\""}
/run_calendar/ {rc = "\""$2"\""}
/exclude_calendar/ {ec = "\""$2"\""}
/days_of_week/ {dow = "\""$2"\""}
/run_window/ {ruw = "\""$2"\""}
/start_times/ {gsub("\"",""); st = "\""$2"\""}
/^start_mins/ {sm = "\""$2"\""}
/profile/ {prof = "\""$2"\""}
/term_run_time/ {trt = "\""$2"\""}
/watch_file/ {wf = "\""$2"\""}
/watch_interval/ {wi = "\""$2"\""}
/resources/ {res = "\""$2"\""}
END{printf "%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s\n", jn, jt, box, cmd, mcn, own, dc, c, rc, ec, dow, ruw, st, sm, res, prof, trt, wf, wi}
' < <(autorep -j $i -q) > $FILENAME.csv
break
done
$i принимает запись wildcard и выдает результат в соответствии с ней.
например: следующие 4 задания имеют в своем названии Test, поэтому я укажу Test% в качестве значения подстановочного знака, и скрипт выдаст результат для всех 4 заданий.
Это тестовые задания, которые я использую:
/* ----------------- Test_A ----------------- */
insert_job: Test_A job_type: CMD
command: sleep 3000
machine: machine1
owner: user1
permission:
date_conditions: 0
term_run_time: 1
alarm_if_fail: 1
alarm_if_terminated: 1
/* ----------------- Test_B ----------------- */
insert_job: Test_B job_type: CMD
command: echo
machine: machine2
owner: user2
permission:
date_conditions: 0
description: "Test"
std_out_file: "/tmp/$AUTO_JOB_NAME.$AUTORUN.out"
std_err_file: "/tmp/$AUTO_JOB_NAME.$AUTORUN.err"
max_run_alarm: 1
alarm_if_fail: 0
alarm_if_terminated: 0
send_notification: 1
/* ----------------- Test_c ----------------- */
insert_job: Test_c job_type: CMD
command: sleep 10
machine: machine3
owner: user3
permission:
date_conditions: 0
alarm_if_fail: 0
alarm_if_terminated: 0
/* ----------------- Test_d ----------------- */
insert_job: Test_d job_type: CMD
command: ls
machine: machine4
owner: user4
permission:
date_conditions: 0
alarm_if_fail: 1
alarm_if_terminated: 1
Но вот проблема: вывод файла csv имеет пустую строку между именами столбцов и данными, как показано ниже:
"insert_job","job_type","box_name","command","machine","owner","date_conditions","condition","run_calendar","exclude_calendar","days_of_week","run_window","start_times","start_mins","resources","profile","term_run_time","watch_file","watch_interval"
,,,,,,,,,,,,,,,,,,
"Test_A","CMD"," ","sleep 3000","machine1","user1","0","0"," "," "," "," "," "," "," "," ","1"," "," "
"Test_B","CMD"," ","echo","machine2","user2","0","0"," "," "," "," "," "," "," "," "," "," "," "
"Test_c","CMD"," ","sleep 10","machine3","user3","0","0"," "," "," "," "," "," "," "," "," "," "," "
"Test_d","CMD"," ","ls","machine4","user4","0","0"," "," "," "," "," "," "," "," "," "," "," "
Требуемый вывод:
"insert_job","job_type","box_name","command","machine","owner","date_conditions","condition","run_calendar","exclude_calendar","days_of_week","run_window","start_times","start_mins","resources","profile","term_run_time","watch_file","watch_interval"
"Test_A","CMD"," ","sleep 3000","machine1","user1","0","0"," "," "," "," "," "," "," "," ","1"," "," "
"Test_B","CMD"," ","echo","machine2","user2","0","0"," "," "," "," "," "," "," "," "," "," "," "
"Test_c","CMD"," ","sleep 10","machine3","user3","0","0"," "," "," "," "," "," "," "," "," "," "," "
"Test_d","CMD"," ","ls","machine4","user4","0","0"," "," "," "," "," "," "," "," "," "," "," "
Я пытался использовать (NR>=1), но это не работает. Я знаю, что это очень тривиально, но я не могу понять это, может кто-нибудь мне помочь?
if (NR>1) может быть там, где ваша проблема. В первый раз, когда это утверждение истинно, все ваши переменные для следующего printf будут пустыми, поэтому на выходе будет пустая запись csv. Изменение проверки на if (NR>3) должно избежать вывода этой пустой записи csv.
@j_b if (NR>1) был вашим кодом, который я взял из одного из моих предыдущих постов stackoverflow.com/questions/74808194/…
Не добавляйте дополнительный вопрос в ЭТОТ вопрос, верните его в исходное состояние, когда вы получили ответы, а затем опубликуйте новый вопрос. Вопросы-хамелеоны категорически не приветствуются.





Вот как надежно (ваш существующий скрипт не будет работать для различных возможных входных значений) и обслуживаемо (если вы хотите добавить/удалить поля для печати или изменить их порядок, просто обновите первый split() аргумент) сделать то, что вы пытаетесь сделать, используя cat file вместо autorep -j $i -q, которого нет в моей системе:
$ cat tst.sh
#!/usr/bin/env bash
cat file |
awk '
BEGIN {
OFS = ","
numTags = split("insert_job job_type box_name command machine owner date_conditions condition run_calendar exclude_calendar days_of_week run_window start_times start_mins resources profile term_run_time watch_file watch_interval",tags)
for ( tagNr=1; tagNr<=numTags; tagNr++ ) {
tag = tags[tagNr]
printf "\"%s\"%s", tag, (tagNr<numTags ? OFS : ORS)
}
}
!NF || /^/\*/ { next }
{ gsub(/^[[:space:]]+|[[:space:]]+$/,"") }
match($0,/[[:space:]]job_type:/) {
if ( jobNr++ ) {
prt()
delete tag2val
}
# save "insert_job" value
tag = substr($1,1,length($1)-1)
val = substr($0,length($1)+1,RSTART-(length($1)+2))
gsub(/^[[:space:]]+|[[:space:]]+$/,"",val)
tag2val[tag] = val
# update $0 to start with "job_type" to look like all other input
$0 = substr($0,RSTART+1)
}
{
tag = val = $0
sub(/:.*/,"",tag)
sub(/[^:]+:[[:space:]]*/,"",val)
tag2val[tag] = val
}
END { prt() }
function prt( tagNr,tag,val) {
for ( tagNr=1; tagNr<=numTags; tagNr++ ) {
tag = tags[tagNr]
val = tag2val[tag]
printf "\"%s\"%s", val, (tagNr<numTags ? OFS : ORS)
}
}
'
$ ./tst.sh
"insert_job","job_type","box_name","command","machine","owner","date_conditions","condition","run_calendar","exclude_calendar","days_of_week","run_window","start_times","start_mins","resources","profile","term_run_time","watch_file","watch_interval"
"Test_A","CMD","","sleep 3000","machine1","user1","0","","","","","","","","","","1","",""
"Test_B","CMD","","echo","machine2","user2","0","","","","","","","","","","","",""
"Test_c","CMD","","sleep 10","machine3","user3","0","","","","","","","","","","","",""
"Test_d","CMD","","ls","machine4","user4","0","","","","","","","","","","","",""
Вышеупомянутое является упрощенной версией моего ответа на ваш предыдущий вопрос, где я предоставил скрипт, который выводит CSV всех полей вместо приведенного выше, который выводит только определенный список полей.
Непонятно, почему у вас есть цикл, вызывающий autorep в вашем существующем скрипте, но если он вам по какой-то причине нужен, скорее всего, вы должны вызывать autorep в цикле и передавать вывод цикла в awk.
while IFS= read -r i; do
autorep -j "$i" -q
done |
awk '...'
вместо вызова autorep и передачи его вывода в awk внутри цикла:
while IFS= read -r i; do
autorep -j "$i" -q |
awk '...'
done
Вышеприведенное было запущено на этой входной копии/вставленной из вашего вопроса:
$ cat file
/* ----------------- Test_A ----------------- */
insert_job: Test_A job_type: CMD
command: sleep 3000
machine: machine1
owner: user1
permission:
date_conditions: 0
term_run_time: 1
alarm_if_fail: 1
alarm_if_terminated: 1
/* ----------------- Test_B ----------------- */
insert_job: Test_B job_type: CMD
command: echo
machine: machine2
owner: user2
permission:
date_conditions: 0
description: "Test"
std_out_file: "/tmp/$AUTO_JOB_NAME.$AUTORUN.out"
std_err_file: "/tmp/$AUTO_JOB_NAME.$AUTORUN.err"
max_run_alarm: 1
alarm_if_fail: 0
alarm_if_terminated: 0
send_notification: 1
/* ----------------- Test_c ----------------- */
insert_job: Test_c job_type: CMD
command: sleep 10
machine: machine3
owner: user3
permission:
date_conditions: 0
alarm_if_fail: 0
alarm_if_terminated: 0
/* ----------------- Test_d ----------------- */
insert_job: Test_d job_type: CMD
command: ls
machine: machine4
owner: user4
permission:
date_conditions: 0
alarm_if_fail: 1
alarm_if_terminated: 1
Эд Мортон, ваш скрипт работает очень хорошо, для первого split( ) аргумента, если в тегах есть место, то как их разделить. я имею в виду, что если вместо insert_job я хочу использовать insert job, то как заставить скрипт воспринимать его как одну строку?
Есть несколько разных вещей, которые могут означать, и несколько разных способов реализации решения, но в целом, если вы хотите использовать теги в строке заголовка, которые отличаются от тегов в ваших данных (например, insert job в заголовке, но insert_job в данных ), затем вам нужно предоставить алгоритм или сопоставление между двумя, поэтому примите ответ на вопрос, который вы задали здесь, когда будете готовы это сделать, а затем задайте дополнительный вопрос с образцом ввода/вывода, который демонстрирует ваши требования к этому новому проблема.
Вот рубин для этого:
ruby -e '
scan1=/^/\*[ \ta-zA-Z_-]+\*/\R+([\s\S]*?)(?=(?:^/\*[ \t-]+)|\z)/
scan2=/([^ \t\n\r:]+): ([^ \t\n\r:]+)/
headers= "insert_job job_type box_name command machine owner
date_conditions condition run_calendar exclude_calendar
days_of_week run_window start_times start_mins resources
profile term_run_time watch_file watch_interval".
split.map{|e| "\"#{e}\""}
data=$<.read.
scan(scan1).
map{|block| block[0].scan(scan2)}
hsh=Hash.new {|h,k| h[k] = [""]*data.length}
data.each_with_index{|r,i|
r.to_h.each{|k,v| hsh[k][i]=v}
}
puts headers.join(",")
hsh.values.transpose.
each{|r| puts r.map{|e| e.match(/^".*"$/) ? e : "\"#{e}\""}.join(",")}
' file
Отпечатки:
"insert_job","job_type","box_name","command","machine","owner","date_conditions","condition","run_calendar","exclude_calendar","days_of_week","run_window","start_times","start_mins","resources","profile","term_run_time","watch_file","watch_interval"
"Test_A","CMD","sleep","machine1","user1","0","1","1","1","","","","",""
"Test_B","CMD","echo","machine2","user2","0","","0","0","Test","/tmp/$AUTO_JOB_NAME.$AUTORUN.out","/tmp/$AUTO_JOB_NAME.$AUTORUN.err","1","1"
"Test_c","CMD","sleep","machine3","user3","0","","0","0","","","","",""
"Test_d","CMD","ls","machine4","user4","0","","1","1","","","","",""
И вот рубин, чтобы сделать второй:
ruby -e '
scan1=/(\S[\s\S]*?)(?=(?:^$)|\z)/
scan2=/(^[^:]+):[ \t]+(.*)/
data=$<.read.
scan(scan1).
map{|block| block[0].scan(scan2)}.
map{|s| s.to_h}
hsh=Hash.new{|h,k| h[k] = [""]*data.length}
data.each_with_index{|h, i| h.each{|k,v| hsh[k][i]<<v}}
puts hsh.keys.map{|e| "\"#{e}\""}.join(",")
hsh.values.transpose.
each{|r| puts r.map{|e| e.match(/^".*"$/) ? e : "\"#{e}\""}.join(",")}
' file
Отпечатки:
"Machine Name","Type","Node Name","Agent Name","Operating System","Agent Release","Agent Build"
"machine1machine2","aa","machine1.testmachine2.test","AGENTAGENT","Windows Server 2012 Windows Server 2012 for amd64","12.012.0","6181, Service Pack 00, Maintenance Level 006181, Service Pack 00, Maintenance Level 00"
"machine1machine2","aa","machine1.testmachine2.test","AGENTAGENT","Windows Server 2012 Windows Server 2012 for amd64","12.012.0","6181, Service Pack 00, Maintenance Level 006181, Service Pack 00, Maintenance Level 00"
Вы смотрели, помогает ли этот ответ вашей проблеме: stackoverflow.com/questions/21489237/…