0

I have a bunch of text files in a directory, where the following word occurs:

GSM89103AATF

Actually, the number can change, so another example could be GSM89089AATF. I need to replace these occurrences with GSM89089\nAATF, that is, insert a new line. Can I do this with sed?

2

You can with GNU sed:

 $ sed -r 's/(GSM[0-9]{5})(AATF)/\1\n\2/' file.in >file.out

The pattern matches the first part and then the second part in two separate capture groups. I have assumed that the first part always will be GSM followed by five digits. The replacement simply pastes in the captured data from the two groups with a newline in-between.

The -r is needed because I've used an extended regular expression. Some implementations of sed use -E instead of -r for these kind of regular expressions.

On systems without GNU sed:

$ sed 's/\(GSM[0-9]\{5\}\)\(AATF\)/\1\
> \2' file.in >file.out

That is, use BRE instead of ERE (and drop the -r GNU extension) just add a \ and press return after \1, and continue the replacement pattern on the next line. > is a prompt, not something you type.

  • 1
    Thank you! You have saved my life. I made a mistake in some simulations output, and thanks to this I don't have to run the whole thing again :) – becko Aug 27 '17 at 11:44
  • I am getting an error, does not recognize option -r. I am on Mac, seems it is not supported here. Any workaround? – becko Aug 27 '17 at 12:26
  • 1
    @becko Ah, use -E instead, it does the same thing. – Kusalananda Aug 27 '17 at 12:26
  • 1
    Nevermind, I installed gsed with brew to avoid all this nonsense. With gsed your first command works like a charm. Thanks. – becko Aug 27 '17 at 12:39
  • 1
    for EREs, GNU sed came up with -r while BSDs came up with -E approximately at the same time, some BSDs have (recently) added support for -r as an alias for -E for compatibility with GNU sed, while GNU sed has added -E for compatibility with BSD (now documented as -E is going to make it to POSIX). – Stéphane Chazelas Feb 20 at 17:22
0

This works on my mac and various linux distributions:

#!/usr/bin/env bash

PATTERN="(GSM[0-9]{5})(AATF)"

sed -E -e $"s_${PATTERN}_\1\\
\2_g" < file_with_values

Where:

  • PATTERN: you can define the patter in a variable, making substitution expression easier to read
  • sed -E -e: set sed to use extended regex (-E) and to use the provided script (-e)
  • $"...": is used to translate strings, and allows variables. Have a look here: bash quoting. It might not be safe in every situation, but in your case it should be fine
  • s_ ..._...\2_g: is the substitution string; I'm using _ as delimiters, so that you don't need to escape / and given that you need capture groups (\1 and \2), it just makes the string easier to read. Please do note the \\ followed by the new line. $"..." allows the use of new lines

If you don't need variables, you can use $'....' that is the dollar sign with single quotes. In that case, you can use \n but you can not insert a new line

The use of $"..." seem to be quite portable: my code, with a similar implementation, runs on docker alpine, centos, debian, fedora, ubuntu.

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.