My input file is of the form:
0 1 0 0 0 1 1 0 0 0 / 1 0 / 1 0 / 1
0 1 0 3/4 1 0 0 1/4 0 0 -1 1/2
0 -1 0 1/4 -1 0 0 3/4 0 0 1 1/2
I want to rearrange the order of the lines that have the fraction within them. Currently I have:
#!bin/bash
filename="input.txt"
while ((i++)); read -r line; do
re='[0-9][/][0-9]';
if [[ $line =~ $re ]]
then
echo $line
fi
done < "$filename"
which will echo the second and third line. Is there an awk or sed command I could use to get these two lines to change their order (leaving the first as is) to being
$1,$2,$3,$5,$6,$7,$9,$10,$11,$4,$8,$12
which would make my file now look like
0 1 0 0 0 1 1 0 0 0 / 1 0 / 1 0 / 1
0 1 0 1 0 0 0 0 -1 3/4 1/4 1/2
0 -1 0 -1 0 0 0 0 1 1/4 3/4 1/2
you can easily do this with awk, nonetheless I think it is important to define the rules of the game a bit.
Under the following assumptions :
- A fraction is anything of the form :
a/b
or a / b
or a/ b
- If a fraction appears in column 4 or 8, reshuffle the columns.
- you want to keep the formatting correct
With this in mind, you can use the following awk code
awk 'BEGIN{format="%4s%6s%6s%6s%6s%6s%6s%6s%6s%7s%7s%7s\n"}
{ gsub(/[[:blank:]]*\/[[:blank:]]*/,"/",$0); $0=$0 }
($4 ~ /\//) || ($8 ~ /\//) {
$12=$4" "$8" "$12
$4=""; $8=""
$0=$0
}
{ printf format,$1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12 }
' file.txt
This does the following :
replace all " / "
or any variant on that by a single /
$0 = $0
redefines the fields, i.e. in your first two lines, you
will move from 18 fields to 12
if a fraction (i.e. a /
) appears in field 4 or 8, then redefine field 12, delete field 4 and 8 and do $0=$0
again.
print with the correct format.
NOTE: in the above example, the fractions have a different output (no spaces)
The above will give you the following output :
0 1 0 0 0 1 1 0 0 0/1 0/1 0/1
0 1 0 1 0 0 0 0 -1 3/4 1/4 1/2
0 -1 0 -1 0 0 0 0 1 1/4 3/4 1/2
If you do not want change your fractions in the first line, then you can do it very easy like this
awk 'BEGIN{format="%4s%6s%6s%6s%6s%6s%6s%6s%6s%7s%7s%7s\n"}
(NF>12) { print; next }
{
$12=$4" "$8" "$12
$4=""; $8=""
$0=$0
printf format,$1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12
}
' file.txt
Here you assume, that
if a line has more then 12 fields, just print it
otherwise, shuffle the columns
This is however less robust as everything depends how the fractions are typed in the 4th,8th and 12th column. I.e. they must be typed without spaces. Output will look like :
0 1 0 0 0 1 1 0 0 0 / 1 0 / 1 0 / 1
0 1 0 1 0 0 0 0 -1 3/4 1/4 1/2
0 -1 0 -1 0 0 0 0 1 1/4 3/4 1/2
This is better to be done using awk
:
awk -v OFS='\t' '/[0-9]\/[0-9]/{print $1,$2,$3,$5,$6,$7,$9,$10,$11,$4,$8,$12; next} 1' file
0 1 0 0 0 1 1 0 0 0 / 1 0 / 1 0 / 1
0 1 0 1 0 0 0 0 -1 3/4 1/4 1/2
0 -1 0 -1 0 0 0 0 1 1/4 3/4 1/2
@anubhava is a better solution than me. Since I wrote the other code, mind as well.
#!/bin/bash
filename="input.txt"
awk '
{
for (i=1; i <= NF; i++)
if ( $(i+1) == "/" || $i == "/" || $(i-1) == "/") {
printf "MM%sMM",$i" "$(i+1)" "$(i+2)
i = i+2
} else if ( match ($i, /^[[:digit:]]\/[[:digit:]]/) ) {
printf "MM%sMM",$i
} else {
printf "MM%sMM",$i
}
printf "\n"
}' $filename | sed -e 's/MMMM/MM/g;s/^MM//;s/MM/\t/g'