Prince H
Prince H

Reputation: 95

How to move first column to last column in unix?

This is the data in a text file.

0.354167 male atyp_angina 0.066038 0.1621 t normal 0.648855 no 0 up 0 reversable_defect <50
0.625 male typ_angina 0.792453 0.328767 f left_vent_hyper 0.564885 no 0.677419 down 0 reversable_defect <50
0.645833 male non_anginal 0.433962 0.134703 f left_vent_hyper 0.641221 no 0.483871 flat 0 normal >50_1
0.666667 female asympt 0.481132 0.413242 f left_vent_hyper 0.572519 yes 0.16129 flat 0 reversable_defect >50_1
0.270833 male typ_angina 0.509434 0.269406 f left_vent_hyper 0.816794 no 0.129032 up 0.666667 normal <50

I have to move first column contains numeric data to the last column for every row.

For eg:

0.354167 male atyp_angina 0.066038 0.1621 t normal 0.648855 no 0 up 0 reversable_defect <50

TO

male atyp_angina 0.066038 0.1621 t normal 0.648855 no 0 up 0 reversable_defect <50 0.354167

How can I do using bash commands?

Upvotes: 3

Views: 2750

Answers (6)

Gilles Qu&#233;not
Gilles Qu&#233;not

Reputation: 185881

With a short Perl one-liner:

perl -anE 'say join " ", @F[1..$#F,0]' file
  • @F is the array fed by (auto)split on spaces (by default, like awk) with the -a switch
  • 1..$#F,0 is an array slice

Upvotes: 0

James Brown
James Brown

Reputation: 37464

In awk. Straightforward, find the first space, `print after it and before it:

$ awk '{
    match($0," ")                                         # find space
    print substr($0,RSTART+RLENGTH),substr($0,1,RSTART)   # print around it
}' file
male atyp_angina 0.066038 0.1621 t normal 0.648855 no 0 up 0 reversable_defect <50 0.354167 
male typ_angina 0.792453 0.328767 f left_vent_hyper 0.564885 no 0.677419 down 0 reversable_defect <50 0.625 
...

or the play with the fields: Store the first field to t then starting from the first field replace it with the next field. Replace the last field with the t:

$ awk '{t=$1;for(i=1;i<NF;i++)$i=$(i+1);$NF=t}1' file
male atyp_angina 0.066038 0.1621 t normal 0.648855 no 0 up 0 reversable_defect <50 0.354167
...

Explained:

$ awk ' 
{
    t=$1               # store 1st to t
    for(i=1;i<NF;i++)  # iterate all but the last field
        $i=$(i+1)      # replacing with the next
    $NF=t              # then the last is replaced with t
}1                     # output
' file

Upvotes: 4

RomanPerekhrest
RomanPerekhrest

Reputation: 92904

Short awk solution (without loop though all fields):

awk '{ $(NF+1)=$1; sub(/^[^ ]+ */,"") }1' file.txt
  • $(NF+1)=$1 - append the 1st field to the end (as the last field)

  • sub(/^[^ ]+ */,"") - remove the 1st field with following space(s)


The output:

male atyp_angina 0.066038 0.1621 t normal 0.648855 no 0 up 0 reversable_defect <50 0.354167
male typ_angina 0.792453 0.328767 f left_vent_hyper 0.564885 no 0.677419 down 0 reversable_defect <50 0.625
male non_anginal 0.433962 0.134703 f left_vent_hyper 0.641221 no 0.483871 flat 0 normal >50_1 0.645833
female asympt 0.481132 0.413242 f left_vent_hyper 0.572519 yes 0.16129 flat 0 reversable_defect >50_1 0.666667
male typ_angina 0.509434 0.269406 f left_vent_hyper 0.816794 no 0.129032 up 0.666667 normal <50 0.270833

Upvotes: 7

Ed Morton
Ed Morton

Reputation: 204731

Since this is a simple substitution on individual lines, it's a perfect job for sed:

$ sed 's/\([^ ]*\) \(.*\)/\2 \1/' file
male atyp_angina 0.066038 0.1621 t normal 0.648855 no 0 up 0 reversable_defect <50 0.354167
male typ_angina 0.792453 0.328767 f left_vent_hyper 0.564885 no 0.677419 down 0 reversable_defect <50 0.625
male non_anginal 0.433962 0.134703 f left_vent_hyper 0.641221 no 0.483871 flat 0 normal >50_1 0.645833
female asympt 0.481132 0.413242 f left_vent_hyper 0.572519 yes 0.16129 flat 0 reversable_defect >50_1 0.666667
male typ_angina 0.509434 0.269406 f left_vent_hyper 0.816794 no 0.129032 up 0.666667 normal <50 0.270833

Upvotes: 4

RavinderSingh13
RavinderSingh13

Reputation: 133780

Following awk will fulfill your question.

Solution 1st:

awk '{for(i=2;i<=NF;i++){printf("%s%s",$i,i==NF?" "$1"\n":" ")}}'   Input_file

Output will be as follows.

male atyp_angina 0.066038 0.1621 t normal 0.648855 no 0 up 0 reversable_defect <50 0.354167

Explanation: Traversing through all the fields starting from 2nd field to NF(total number of fields) value. Here I am using printf to print the values so there are 2 strings which I am looking to print 1st is off course field's value and second is to check if variable i's value is equal to NF means we reached to last field then print space first field and new line(as per OP's request) else(if i's value is NOT equal to NF) then print simple space.

EDIT: I ran my command to complete Input_file too now and seems to be fine as follows is the output.

awk '{for(i=2;i<=NF;i++){printf("%s%s",$i,i==NF?" "$1"\n":" ")}}'  Input_file
male atyp_angina 0.066038 0.1621 t normal 0.648855 no 0 up 0 reversable_defect <50 0.354167
male typ_angina 0.792453 0.328767 f left_vent_hyper 0.564885 no 0.677419 down 0 reversable_defect <50 0.625
male non_anginal 0.433962 0.134703 f left_vent_hyper 0.641221 no 0.483871 flat 0 normal >50_1 0.645833
female asympt 0.481132 0.413242 f left_vent_hyper 0.572519 yes 0.16129 flat 0 reversable_defect >50_1 0.666667
male typ_angina 0.509434 0.269406 f left_vent_hyper 0.816794 no 0.129032 up 0.666667 normal <50 0.270833

Upvotes: 2

glenn jackman
glenn jackman

Reputation: 247250

Perl is handy for text manipulation:

perl -lane 'push @F, shift @F; print "@F"' file

Upvotes: 5

Related Questions