4

I have a file with the following format:

A 485C72F95C72E15C EXTERNAL
B CC32480A3247F84A SYSTEM
C EC2A63F12A63B76C EXTERNAL

I want to supply the letter in the first column using the value of the variable 'letter', and replace the value in the second column with a value I supply in the variable 'id'. The third column may or may not differ or match in any case. The first and second columns will never contain spaces or special characters.

I've tried to use sed, but my sed-fu is not strong. I came up with this:

letter=A
id=MYNEWIDSTRING
sed "/$letter /s/[^ ]*/$id/2"

The output is:

A MYNEWIDSTRING EXTERNAL
B MYNEWIDSTRING SYSTEM
C EC2A63F12A63B76C EXTERNAL

The id is replaced in two lines, I'm assuming this is due to 'A ' being matched at the end of the original id string.

I know to use sed -i to edit the file inplace, but not doing it yet, as my command is still a bit dodgy.

Where have I gone wrong, or should I be using a different method?

5

Anchor it (^ is start of line) so that the A is only matched if it's the first character:

$ letter=A; id=MYNEWIDSTRING; sed "/^$letter /s/[^ ]*/$id/2" file
A MYNEWIDSTRING EXTERNAL
B CC32480A3247F84A SYSTEM
C EC2A63F12A63B76C EXTERNAL

by the way, if you want to pass variables to sed but you need strong quoting remember you can turn quoting on and off while adding double quotes for the variables - ugly but probably best practice in general:

sed '/^'"$letter"' /s/[^ ]*/'"$id"'/2'
  • Oh what an anchor I am! So simple! I was almost there! – Arronical Nov 3 '16 at 13:53
  • ^_^ thanks for kindly not quite getting there and thus giving me an excuse to play with sed – Zanna Nov 3 '16 at 13:55
  • The quoting stuff is very useful too, I always feel worried about unquoted variables! – Arronical Nov 3 '16 at 13:57
  • me too haha I'm sure I err on the side of overquoting – Zanna Nov 3 '16 at 13:59
5

Anytime you are dealing with structured data, I'd reach for awk or perl rather than sed.

For example

awk -v letter="A" -v id="MYNEWIDSTRING" '$1 == letter {$2=id}1' file
A MYNEWIDSTRING EXTERNAL
B CC32480A3247F84A SYSTEM
C EC2A63F12A63B76C EXTERNAL

or

perl -alne '
  BEGIN{$letter = shift; $id = shift;} 
  print join " ", $F[0], $F[0] eq $letter ? $id : $F[1], @F[2..$#F]
' 'A' 'MYNEWIDSTRING' file

Newer versions of GNU awk have a -i (--in-place) flag; in others you would need to use an explicit temporary file; perl should have a -i in any case.

  • Nice, I've been using awk to read the data from the file, and hadn't realised that it was useful for editing too. – Arronical Nov 3 '16 at 14:31
  • I'm on 14.04, turns out my (g)awk is version 4.0.1 and this was introduced in version 4.1.0. Useful to know for future reference though. – Arronical Nov 3 '16 at 14:43

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.