once
once

Reputation: 1399

Rearrange column with empty values using awk or sed

i want to rearrange the columns of a txt file, but there are empty values, which cause a problem. For example:

testfile:

Name    ID      Count   Date    Other
A       1       10      513     x
        6       15      312     x
        3       18      314     x
B       19      31      942     x
        8       29      722     x

when i tried $ more testfile |awk '{print $2"\t"$1"\t"$3"\t"$4"\t"$5}' it becomes:

ID      Name    Count   Date    Other
1       A       10      513     x
15      6       312     x
18      3       314     x
19      B       31      942     x
29      8       722     x

which is not i want, please help,i want it to be

ID      Name    Count   Date    Other
1       A       10      513     x
15              6       312     x
18              3       314     x
19      B       31      942     x
29              8       722     x

moreover i am not sure which columns might contain empty values, and the column length is not fixed, thank you

Upvotes: 1

Views: 202

Answers (3)

paxdiablo
paxdiablo

Reputation: 881983

The most natural model for awk to use is columns as defined by the transitions from white-space to non-white-space and back. Since you have columns that may themselves be white-space, the natural model won't work.

However, you can revert to using a model based on column positions rather than transitions, meaning that a file containing only spaces (the presence of tabs will complicate things):

Name    ID      Count   Date    Other
A       1       10      513     x
        6       15      312     x
        3       18      314     x
B       19      31      942     x
        8       29      722     x

can still be rearranged, though not as succinctly as transition-based columns.

The following awk script will do the trick, swapping name and id:

{
    name  = substr($0, 1,7);
    id    = substr($0, 9,7);
    count = substr($0,17,7);
    date  = substr($0,25,7);
    other = substr($0,33  );
    print id" "name" "count" "date" "other;
}

If the original file is called pax.in and the awk script is stored in pax.awk, the command awk -f pax.awk pax.in will give you, as desired:

ID      Name    Count   Date    Other
1       A       10      513     x
6               15      312     x
3               18      314     x
19      B       31      942     x
8               29      722     x

Keep in mind I've written that script to be relatively flexible, allowing you to change the order of the columns quite easily. If all you want is to swap the first two columns, you could use:

awk '{print substr($0,9,8)substr($0,1,8)substr($0,17)}' qq.in

or the slightly shorter (if you're allowed to use other tools):

sed -E 's/^(.{8})(.{8})/\2\1/' qq.in

Upvotes: 1

Ed Morton
Ed Morton

Reputation: 203924

Assuming your input file is not tab-separated and you have (or can get) GNU awk then I recommend:

$ awk -v FIELDWIDTHS="8 8 8 8 8" -v OFS='\t' '{
    for (i=1;i<=NF;i++) {
        gsub(/^\s+|\s+$/,"",$i)
    }
    t=$1; $1=$2; $2=t'
}1' file
ID      Name    Count   Date    Other
1       A       10      513     x
6               15      312     x
3               18      314     x
19      B       31      942     x
8               29      722     x

If your file is tab-separated then all you need is:

awk 'BEGIN{FS=OFS="\t"} {t=$1; $1=$2; $2=t}1' file

Upvotes: 2

karakfa
karakfa

Reputation: 67507

Another awk alternative is using the number of fields. If you know your data and it's only deficit in the first column you can try this.

awk -v OFS="\t" 'NF==4{$5=$4;$4=$3;$3=$2;$2=$1;$1=""} {print $2,$1,$3,$4,$5}'

However, the output will be tab separated instead of fixed length format. You can achieve the same using printf and changing OFS, but perhaps tab separated is what you really need for tabular representation.

Upvotes: 1

Related Questions