1

I have a file in which the first column is to be changed, for example, I have the following file (In the original file I have multiple columns but truncating the following to 2 columns, it may have empty lines at the end of the file).

test.txt:

0 a
2 b  
3 c 
4 d
5 e


I need to change the contents of the first column from, 0 -> 2, 2 -> 3 , 3 -> 5 , 4 -> 0, 5 -> 4 and my final file should become,

2 a
3 b
5 c
0 d
4 e


I tried using awk as follows,

awk '$1=="0"{$1="2"} $1=="2"{$1="3"} $1=="3"{$1="5"} $1=="4"{$1="0"} $1=="5"{$1="4"};1' test.txt

but as awk doesn't read line by line and change the required contents, the output was,

4 a
4 b
4 c
0 d
4 e


Can anyone help me with converting to what I need, python, sed, or awk, or any scripting tool is welcomed.

0
1

AWK actually reads line by line, and you will only needed to add next statement after printing for every assignments, so the rest of the codes will be skipped.

awk '$1=="0"{ $1="2"; print; next }
     $1=="2"{ $1="3"; print; next }
     $1=="3"{ $1="5"; print; next }
     $1=="4"{ $1="0"; print; next }
     $1=="5"{ $1="4"; print; next }1' infile

or instead using a control flag:

awk '!s && $1=="0"{ $1="2"; s=1 }
     !s && $1=="2"{ $1="3"; s=1 }
     !s && $1=="3"{ $1="5"; s=1 }
     !s && $1=="4"{ $1="0"; s=1 }
     !s && $1=="5"{ $1="4"; s=1 }
                  { print; s=0  }' infile

But you could also do it all as like following:

awk -F'( )' 'BEGIN{ split("2 1 3 5 0 4", map) }
$1!=""{ $1=($1+1 in map)?map[$1+1]:$1 }1' infile

with the split(string, arryName) function we create an array called map with the indexes and values as following that splits based on the FS (default is Space/Tabs)

Index        Value
map[<0>+1] -->   2
map[<1>+1] -->   we choice it 1 so it will be unchanged for <1> --> 1
map[<2>+1] -->   3
map[<3>+1] -->   5
map[<4>+1] -->   0
map[<5>+1] -->   4

<#> the number within angles are the values from the first column and since array's indexes in awk starts from 1 not 0, so we are adding one to column value and then get the corresponding value from the map array.


To be generalized solution (but I will still use above one since almost the user defined keys/values are sequential and that array indexes can be used as the keys, but) here you go if that is otherwise:

awk -F'( )' 'BEGIN{ len=split("0 2 2 3 3 5 4 0 5 4", map) }
{ for(i=1; i<=len/2; i+=2 ) if($1==map[i]){ $1=map[i+1]; break} }1' infile
0
1
$ awk 'BEGIN{split("1 3 5 0 4",map); map[0]=2} {$1=map[$1]} 1' file
2 a
3 b
5 c
0 d
4 e



1

With the shell:

while read -r idx rest; do
  case $idx in 
    0) idx=2 ;; 
    2) idx=3 ;; 
    3) idx=5 ;; 
    4) idx=0 ;; 
    5) idx=4 ;;
  esac 
  echo "$idx $rest"
done < test.txt

To write the output back to the original file, one of

tmp=$(mktemp)
while ... < test.txt > "$tmp" && mv "$tmp" test.txt

or install moreutils and

while ... < test.txt | sponge test.txt

Or perl:

perl -pe '
    BEGIN {%map = (0=>2, 2=>3, 3=>5, 4=>0, 5=>4)}
    s{(\d+)}{$map{$1} // $1}e
' test.txt
1

Using GNU sed with extended regex mode turned ON -E. We first isolate the first column and run the y/// command which shall transliterate the pattern space (now it has just the first column) according to the scheme. Then we recall the original line and take the 2nd column onwards from it and discard the original first column.

sed -e '
  /^\S\s/!b
  s//&\n/;h
  s/\n.*//
  y/02345/23504/
  G;s/\n.*\n//
' file

2 a
3 b
5 c
0 d
4 e

Other approaches can be:

perl -lpe '
  s/^\S\s/
      $& =~ tr[02345]
              {23504}r
  /ex;
' file

Or as a ine-liner:

perl -lpe 's|^\S\s|$& =~ tr/02345/23504/r|e' file
python3 -c 'import sys
ifile = sys.argv[1]
with open(ifile) as fh:
  for l in fh:
    l = l.strip()
    p = l.find(" ")
    if p == 1:
      f1,rest = l[:p],l[p:];print(f1.translate(f1.maketrans("02345","23504")),rest,sep="")
    else:print(l)
' file

awk -v u="02345" -v v="23504" '
  BEGIN {
    gsub(/./, "&" FS, u)
    gsub(/./, "&" FS, v)
    split(u, a)
    for (i=1; i<=split(v,b); i++)
      c[a[i]] = b[i]
  }
  $1 in c{$1=c[$1]}1
' file
1
  • 1
    Fixed now. I misunderstood the input specs.Thanks.
    – guest_7
    Jun 7 at 17:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.