I have a long running program, my_prog that has some output that I want to parse to get two variables, $start and $end. Here's what the output might look like:
Important data between the first set of pipes|3|a| This line is not interesting to me|5|c| ... Another line with data (at the end this time)|4|b|
In the example above, I just need:
start=3 end=b
I'm using this in a bash script. I have a feeling awk can totally solve this issue, but doing a start=$(my_prog|awk ...)
will g开发者_运维问答ive only one variable. I guess I could do a my_array=($(my_prog|awk ...))
, but that just seems messy. Also, I don't want to put the (possibly long) output of my_prog into a variable. What's a good, simple way to get that data? Can awk somehow write directly to the bash variables?
as @Zack wrote awk script is ok, the only improvement could be:
read start end < <(my_prog |
awk -F\| 'NR==1 { start=$2 } END { print start " " $3 }')
This is how I would do it (totally untested):
startend=$(my_prog |
awk -F\| 'NR==1 { start=$2 } { end=$3 } END { print start "|" end }')
start=${startend%|*}
end=${startend#*|}
There's no need to do an assignment on each line of the file. The last record is available in the END
clause so you won't even need to do an assignment there.
Also, AWK keeps a separate OFS (output field separator) so you can use a comma between your output variables when you print them.
delim=" " # or choose one that suits you
read -r -d "$delim" start end < <(my_prog |
awk -F\| -v OFS="$delim" 'NR==1 { start=$2 } END { print start, $3 }')
Alternatively, instead of process substitution < <()
, you can use a here string or a here doc:
read ... <<< $(my_prog ...)
or
read ... <<EOF
$(my_prog ...)
EOF
To neaten up the read assignment, you can put your my_prog/awk pipe in a function:
foo () { my_prog | awk ... ; }
read ... < <(foo) # or one of the other redirection methods
One could also eval:
eval `myprog | awk -F\| 'NR==1 { start=$2 } { end=$3 } END { print "start="start " end="end }'`
精彩评论