0

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
Rob S.
  • 35
  • 7
  • @anubhava edited – Rob S. Nov 10 '17 at 04:03
  • 3
    Hah! [I remember this format!](https://stackoverflow.com/q/47214248/1072112) :-) – ghoti Nov 10 '17 at 04:07
  • I know, I am just trying to think of a better way of describing my problem and it's probably just making things worse. Starting to think I won't get this figured out and will just have to manually change all lines – Rob S. Nov 10 '17 at 04:11
  • With which character are your columns separated? Do the lines contain a leading separator? – Cyrus Nov 10 '17 at 04:19

3 Answers3

3

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
  • 761,203
  • 64
  • 569
  • 643
0

@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' 
Daein Park
  • 4,393
  • 2
  • 12
  • 21
0

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
kvantour
  • 25,269
  • 4
  • 47
  • 72
  • @RobS. If you have a modern version of gawk you could do inplace replacements (Ref [here](https://stackoverflow.com/questions/16529716/awk-save-modifications-in-place)). Just replace `awk` by `gawk -i inplace`. If your version of awk does not support the inplace, then you can do `awk '...' file.txt > file.new.txt; mv file.new.txt file.txt`. Basically make a new file and rename it. – kvantour Nov 10 '17 at 16:22
  • The gawk did not work but the simple write the output to a new file and move that file did. Greatly appreciate the help! – Rob S. Nov 10 '17 at 16:31