Reputation: 11
I need advice on how to achieve this output:
myoutputfile.txt
Tom Hagen 1892
State: Canada
Hank Moody 1555
State: Cuba
J.Lo 156
State: France
output of mycommand:
/usr/bin/mycommand
Tom Hagen
1892
Canada
Hank Moody
1555
Cuba
J.Lo
156
France
Im trying to achieve with this shell script:
IFS=$'\r\n' GLOBIGNORE='*' :; names=( $(/usr/bin/mycommand) )
for name in ${names[@]}
do
#echo $name
echo ${name[0]}
#echo ${name:0}
done
Thanks
Upvotes: 1
Views: 91
Reputation: 437110
bash
solution is simple and elegant, but slow with large input files (loops in bash
are slow).xargs
(verify with xargs --version
), but also does not perform well with large input files (external utility printf
is called once for every 3 input lines).If performance matters, try the following awk
solution:
/usr/bin/mycommand | awk '
{ ORS = (NR % 3 == 1 ? " " : "\n")
gsub("^[[:blank:]]+|[[:blank:]]*\r?$", "") }
{ print (NR % 3 == 0 ? "State: " : "") $0 }
' > myoutputfile.txt
NR % 3
returns the 0-based index of each input line within its respective group of consecutive 3 lines; returns 1
for the 1st line, 2
for the 2nd, and 0
(!) for the 3rd.{ ORS = (NR % 3 == 1 ? " " : "\n")
determines ORS
, the output-record separator, based on that index: a space for line 1, and a newline for lines 2 and 3; the space ensures that line 2 is appended to line 1 with a space when using print
.gsub("^[[:blank:]]+|[[:blank:]]*\r?$", "")
strips leading and trailing whitespace from the line - including, if present, a trailing \r
, which your input seems to have.{ print (NR % 3 == 0 ? "State: " : "") $0 }
prints the trimmed input line, prefixed by "State: " only for every 3rd input line, and implicitly followed by ORS
(due to use of print
).Upvotes: 1
Reputation: 4681
An easy one-liner (not tuned for performance):
/usr/bin/mycommand | xargs -d '\n' -L3 printf "%s %s\nState: %s\n"
It reads 3 lines at a time from the pipe and then passes them to a new instance of printf
which is used to format the output.
If you have whitespace at the beginning (it looks like that in your example output), you may need to use something like this:
/usr/bin/mycommand | sed -e 's/^\s*//g' | xargs -d '\n' -L3 printf "%s %s\nState: %s\n"
Upvotes: 2
Reputation: 1059
#!/bin/bash
COUNTER=0
/usr/bin/mycommand | while read LINE
do
if [ $COUNTER = 0 ]; then
NAME="$LINE"
COUNTER=$(($COUNTER + 1))
elif [ $COUNTER = 1 ]; then
YEAR="$LINE"
COUNTER=$(($COUNTER + 1))
elif [ $COUNTER = 2 ]; then
STATE="$LINE"
COUNTER=0
echo "$NAME $YEAR"
echo "State: $STATE"
fi
done
Upvotes: 1
Reputation: 530920
Assuming you can always rely on the command to output groups of 3 lines, one option might be
/usr/bin/mycommand |
while read name;
read year;
read state; do
echo "$name $year"
echo "State: $state"
done
An array isn't really necessary here.
One improvement could be to exit the loop if you don't get all three required lines:
while read name && read year && read state; do
# Guaranteed that name, year, and state are all set
...
done
Upvotes: 3