How to swap the last two column pairs with awk?

Viewed 83

I am trying this

awk '{B=$(NF-1);A=$NF;  $NF=$(NF-2); $(NF-1) = $(NF-3); $(NF-2)=A; $(NF-3) = B; print;}' input_text.txt

but I get the error:

awk: cmd. line:1: (FILENAME=cazzo.txt FNR=2) fatal: attempt to access field -1

Sample input:

$ cat input_text.txt
1 7 9 11 0 5 2

The same happens if I replace the spaces with tabs in the input_text.txt file.

Expected output:

 1 7 9 5 2 11 0

I am running with Cygwin on Windows 10.

3 Answers

You can try this awk for swapping values:

awk 'NF > 3 {a=$NF; b=$(NF-1); $NF=$(NF-2); $(NF-1)=$(NF-3); $(NF-3)=b; $(NF-2)=a} 1' file

1 7 9 5 2 11 0

If there are DOS line breaks then use:

awk -v RS='\r?\n' 'NF > 3 {a=$NF; b=$(NF-1); $NF=$(NF-2); $(NF-1)=$(NF-3); $(NF-3)=b; $(NF-2)=a} 1' file

If you have gnu awk then you can use this regex based approach:

awk -v RS='\r?\n' 'NF > 3 {
$0 = gensub(/(\S+\s+\S+)(\s+)(\S+\s+\S+)$/, "\\3\\2\\1", "1")} 1' file

1 7 9 5 2 11 0

To swap the last n fields with the n fields before them:

$ awk -v n=2 'NF>=(2*n){ for (i=NF-(n-1); i<=NF; i++) {t=$i; $i=$(i-n); $(i-n)=t} } 1' file
1 7 9 5 2 11 0

$ awk -v n=3 'NF>=(2*n){ for (i=NF-(n-1); i<=NF; i++) {t=$i; $i=$(i-n); $(i-n)=t} } 1' file
1 0 5 2 7 9 11

With your shown samples, please try following code. This is a Generic code, where you have 2 awk variables named fromFields and toFields. So you need to give their values like: let's say you want to substitute 4th field value with 6th field AND 5th field value with 7th field, so you will set it like: fromFields="4,5" and toFields="6,7". I am assuming user will understand that values which are given are feasible with respect to Input_file.

awk -v fromFields="4,5" -v toFields="6,7" '
BEGIN{
  num1=split(fromFields,arr1,",")
  num2=split(toFields,arr2,",")
}
{
  tmp=""
  for(i=1;i<=num1;i++){
    tmp=$arr1[i]
    $arr1[i]=$arr2[i]
    $arr2[i]=tmp
  }
}
1
' Input_file
Related