Reputation: 4487
I've got the following list of elements:
a, b, c, 1337, d, e
I wish I have:
e, d, 1337, c, b, a
How can I achieve that in bash?
Upvotes: 7
Views: 6355
Reputation: 47327
You can do this with awk
:
#!/bin/bash
awk 'BEGIN{FS=",[ ]*"; OFS=", "}
{
for (i=NF; i>0; i--) {
printf "%s", $i;
if (i>1) {
printf "%s", OFS;
}
}
printf "\n"
}'
Explanation of the script:
FS=",[ ]*";
: The regex for Field Separator (delimiter for your input) matches a comma followed by zero or more spaces, so your input can be any of:
a, b, c, 1337, d, e
a,b,c,1337,d,e
a, (many spaces) b, c,1337,d, e
OFS=", "
: The Output Field Separator (delimiter for your output) will be explicitly a comma followed by a space (so output looks consistent)for (i=NF; i>0; i--) { ... }
: NF
means the Number of Fields in the current line. Here we iterate backwards, printing from the last field to the first field.if (i>1) { ... }
: Only print the OFS
if it's not the last field in the outputprintf "\n"
: new line.Sample usage:
$ ./script_name < input_file > output_file
Upvotes: 5
Reputation: 247042
bash:
echo "a, b, c, 1337, d, e" | (
IFS=", "
while read line; do
set -- $line
for (( i=$#; i > 1; i-- )); do
printf "%s, " "${!i}"
done
echo "$1"
done
)
I use parentheses to create a subshell so I don't alter the IFS variable in the current shell.
Upvotes: 1
Reputation: 16039
With the following script, it doesn't matter how many elements are in the list:
IFS=', '; read -a array <<< "a, b, c, 1337, d, e"
let i=${#array[@]}-1;
while [ $i -ge 0 ]; do
echo -n "${array[$i]}, ";
let i--;
done
Also, you can use the following perl one-liner (it will add a \n
after the first element though)
echo "a, b, c, 1337, d, e" | perl -ne 'foreach(reverse(split(", ",$_))){print "$_, "}'
Upvotes: 1
Reputation: 2250
$ awk -F", " '{for (i=NF;i;i--) printf "%s ",$i; print ""}' < datafile
e d 1337 c b a
Upvotes: 2
Reputation: 65821
This solution is not very elegant, but should work with any number of fields:
sed 's/, /\n/g' | tac | sed ':a;$!{N;ba};s/\n/, /g'
Either pipe you data to it or give a file as second argument to first sed
(it will print the whole file as one comma-separated line, though).
Upvotes: 2
Reputation: 38456
If your input is simple, and the number of columns is static, you could always go with a hardcoded awk
solution:
awk -F, '{ print $6", "$5", "$4", "$3", "$2", "$1 }'
This assumes that you have 6 columns that are separated by a comma. If you have a "comma + space" delimiter, ,
, you can use -F', '
instead of just -F,
.
A straightforward example usage with output:
$ echo "a, b, c, 1337, d, e" | awk -F', ' '{ print $6", "$5", "$4", "$3", "$2", "$1 }'
e, d, 1337, c, b, a
With a file as input:
awk -F', ' '{ print $6", "$5", "$4", "$3", "$2", "$1 }' your_file
You can then redirect the output from that to another file by appending > reversed_columns
; "reversed_columns" being the name of the new file in this case.
Upvotes: 2