Bajajsahab
Bajajsahab

Reputation: 97

Get a specific character and swap columns in a file

I am trying to get 20th character of each line, if its b then exchange last 2 columns with each other values AND if its B then 3rd last column and last column's value should be exchanged, like shown below.

Sample of input:

1234567891011121314b abcd erfg ijkl 12114353 blabla
1234567891011121314Babcd erfg ijkl 12114353 blabla

Sample of expected output:

1234567891011121314b abcd erfg ijkl blabla 12114353
123456789101112131Babcd erfg blabla 12114353 ijkl

I tried following code:

while read value
do
    echo "$value" | cut -c20
done < "file"

I also tried to use awk's substr but couldn't proceed too much in it too.

Actual file is same like shown sample above; please guide me.

Upvotes: 2

Views: 97

Answers (4)

Sundeep
Sundeep

Reputation: 23677

With perl

perl -lpe 's/^.{19}([bB]).*?\K(\s+\S+)(\s+\S+)(\s+\S+)$/$1 eq "b" ? "$2$4$3" : "$4$3$2"/e'
  • ^.{19}([bB]).*?\K capture the 20th character (only if it is b or B) and ignore all text except last three columns
  • e flag allows Perl code in replacement section
  • $1 eq "b" checks if 20th character is b

With sed (syntax checked with GNU sed, might differ for other implementations), modifying the answer from @costaparas, assuming 20th character is always b or B

sed -E '/^.{19}b/ s/([^ ]+) ([^ ]+)\s*$/\2 \1/; t; s/([^ ]+) ([^ ]+) ([^ ]+)\s*$/\3 \2 \1/'
  • /^.{19}b/ checks if 20th character is b
    • if so, swap last two columns and then unconditionally start next cycle by using t command
  • Otherwise, perform the second substitution
    • add /^.{19}B/ before the second substitution if needed

Upvotes: 1

costaparas
costaparas

Reputation: 5237

If you want to do it the long way using your current approach, you can use sed to finish it off.

Simply check what the 20th character is, and do the appropriate swap in either case using a sed substitution. The swap is achieved using 2 or 3 capture groups, depending on which case the line satisfies.

file='file.txt'

while read -r value
do
    b=$(echo "$value" | cut -c20)
    if [ "$b" = 'b' ]
    then
        echo "$value" | sed -E 's/([^ ]+) ([^ ]+)\s*$/\2 \1/'
    elif [ "$b" = 'B' ]
    then
        echo "$value" | sed -E 's/([^ ]+) ([^ ]+) ([^ ]+)\s*$/\3 \2 \1/'
    fi
done < "$file"

This assumes your fields are space-delimited.

In both cases, we anchor the match to the end of the line, and also account for potential trailing whitespace (which we don't bother substituting back in - but you can if you want to).

Output:

1234567891011121314b abcd erfg ijkl blabla 12114353
1234567891011121314Babcd erfg blabla 12114353 ijkl

Upvotes: 1

Daweo
Daweo

Reputation: 36640

I would use GNU AWK for that task following way, let file.txt content be

12345678910111213141b abcd erfg ijkl 12114353 blabla
12345678910111213141Babcd erfg ijkl 12114353 blabla

then

awk '{lastcol=$NF}/^.{20}b/{$NF=$(NF-1);$(NF-1)=lastcol}/^.{20}B/{$NF=$3;$3=lastcol}{print}' file.txt

output

12345678910111213141b abcd erfg ijkl blabla 12114353
12345678910111213141Babcd erfg blabla 12114353 ijkl

Explanation: for every line store last column content as lastcol, if line startswith 20 of any characters followed by b then set content of last row to what is 2nd from end column and content of 2nd from end column to lastcol, if line startswith 20 of any characters folllowed by B then set content of last column to what is in 3rd column and content of 3rd column to lastcol. print such line.

(tested in gawk 4.2.1)

Upvotes: 2

RavinderSingh13
RavinderSingh13

Reputation: 133650

Based on your shown samples, could you please try following. Written and tested in GNU awk.

awk '
{
  val=substr($0,20,1)
}
val=="b"{
  temp=$(NF-1)
  $(NF-1)=$NF
  $NF=temp
  temp=""
}
val=="B"{
  temp=$(NF-2)
  $(NF-2)=$NF
  $NF=temp
  temp=""
}
1' Input_file

Explanation: Adding detailed explanation for above.

awk '                   ##Starting awk program from here.
{
  val=substr($0,20,1)   ##getting 20th character value here.
}
val=="b"{               ##Checking condition if val is b then do following.
  temp=$(NF-1)          ##Creating temp with 2nd last field value here.
  $(NF-1)=$NF           ##Setting last field value to 2nd last field here.
  $NF=temp              ##Again setting last field as temp.
  temp=""               ##Nullifying temp here.
}
val=="B"{               ##Checking condition if val is B then do following.
  temp=$(NF-2)          ##Creating temp which has 3rd last field value here.
  $(NF-2)=$NF           ##Setting 3rd last field value to last field here.
  $NF=temp              ##Again setting last field as temp.
  temp=""               ##Nullifying temp here.
}
1                       ##Printing current line here.
' Input_file            ##Mentioning Input_file name here.

Upvotes: 3

Related Questions