0

Pattern: abc followed by space or is the last character in a line.

orig="abc[[:space:]]+";
new=Hello
sed -i -r -e "s|${orig}|${new}|g" ./file ;

File:

abc
abcd
abc

abc d

After executing:

abc
abcd
abc

Hellod

Expected Output:

Hello
abcd
Hello

Hello d

What am I missing?


Note: I want to preserve the space character.

  • I noticed that you said "Pattern: abc followed by space or is the last character in a line" but then showed abc d being translated to Hellod when "abc(space)" was not the end of line -- d is. Which rule is correct? abc(spaces) or abc(spaces)(end of line)? – Jeff Schaller Dec 11 '18 at 0:37
  • 1
    Perhaps what you are looking for is a word boundary anchor? s/abc\b/Hello/ or (GNU sed) s/abc\>/Hello/ – steeldriver Dec 11 '18 at 0:47
2

If what you want is to preserve spaces:

Note: I want to preserve the space character.

Then, match them, but restore them on the replacement:

 orig='abc([[:space:]]+)'
 new='Hello\1'
 sed -E -e "s|${orig}|${new}|g" ./infile ;

That will generate this output (to modify in-place add the appropriate -i option):

 Hello  
 abcd  
 Hello   

 Hello d

Of course, that is assuming the file had some spaces at the end of some lines:

 $ cat infile | sed -n l
 abc  $
 abcd  $
 abc   $
 $
 abc d$

If you also need that the regex match lines that do not end on spaces, you need a more complex regex:

 orig='abc([[:space:]]+|$)';
 new='Hello\1';
 sed -E -e "s,${orig},${new},g" ./infile ;

Of course, the s||| delimiter had to be changed to s,,, to avoid conflicts with the | required by the regex for alternative.

  • Why do we have to add |$? According to sed, a stream editor: Character Classes and Bracket Expressions : Space characters: in the ‘C’ locale, this is tab, newline, vertical tab, form feed, carriage return, and space. – Nikhil Dec 11 '18 at 8:55
  • 1
    (1) I tried to match your words: space or is the last character in a line. The only way to tell a regex to match the end of a line is $, no other. The syntax fo an or is |, so that is what I wrote. IF you meant: several spaces or none, the regex would have been abc([[:space:]]*$), no | needed, but the end of line is still required. (Cont...) @Nikhil – Isaac Dec 11 '18 at 9:07
  • 2
    (2) There is no way to match a newline in grep (BRE, ERE or most pcre without a -z option used). That is also said in info grep: Since newline is also a separator for the list of patterns, there is no way to match newline characters in a text. So, the character range may (in some OSes) match a newline but there is never a newline to match in most grep text (exception noted above with grep -Pz or some other corner case uses). @Nikhil – Isaac Dec 11 '18 at 9:08
1

Instead of matching, capturing and then re-inserting the whitespace, just look for "abc" as a standalone word. With GNU sed, use \< and \> as word boundaries:

sed 's/\<abc\>/Hello/g' file
Hello
abcd
Hello

Hello d

If you want to put the pattern and replacement into variables, you just have to be careful to quote the backslashes appropriately.

pattern="\\<abc\\>"    # or: pattern='\<abc\>'
replacement=Hello
sed "s/$pattern/$replacement/" file

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.