4

I have 1 file, for example

12341234 3,0
12341342 4,0

How can I print:

abcdabcd 3,0
abcdacdb 4,0

cat $1 | tr 1234 abcd

changes both column 1 and 2. How to change only 1 column and print all columns?

skuska
  • 53
  • 6
  • 1
    As an aside -- `cat` is best avoided; `tr 1234 abcd <"$1"` is both more reliable (works with filenames with spaces due to the corrected quoting) and faster (lets `tr` read straight from the input file, not from a FIFO). – Charles Duffy Jan 21 '18 at 18:40
  • @BelaVizer, eh? tr maps between character sets. The usage the OP gave works. – Charles Duffy Jan 21 '18 at 18:44

4 Answers4

4

One way to do this is to split the columns and then rejoin them with paste:

paste <(cut -d' ' -f1 <"$1" | tr 1234 abcd) <(cut -d' ' -f2- <"$1")

The <() syntax for process substitution is a bashism, but the required functionality from paste, cut and tr tools is all POSIX-specified; thus, the only thing we require to run that isn't part of the POSIX standard is bash itself.

Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
3

Perl to the rescue:

perl -lane '$F[0] =~ tr/1234/abcd/; print "@F"' -- file
  • -n reads the input line by line
  • -l removes newlines from input and adds them to printed lines
  • -a splits automatically each line on whitespace into the @F array
  • the tr operator works similarly to tr, but you can bind it by the binding operator =~ to only operate on the first column ($F[0]).
choroba
  • 231,213
  • 25
  • 204
  • 289
2

With GNU sed:

sed 'h;s/.* //;x;s/ .*//;y/1234/abcd/;G;s/\n/ /' file

Output:

abcdabcd 3,0
abcdacdb 4,0

See: man sed

Cyrus
  • 84,225
  • 14
  • 89
  • 153
0

Awk solution:

awk 'BEGIN{ split("abcd", a, "") }
     { 
         len=split($1, b, ""); 
         for (i=1; i<=len; i++) printf("%s",(b[i] in a? a[b[i]] : b[i])); 
         print FS $2 
     }'  file

The output:

abcdabcd 3,0
abcdacdb 4,0
RomanPerekhrest
  • 88,541
  • 4
  • 65
  • 105