Find all matches of two-character string in a text file and swap them
sed
supports backreferences to capture groups defined in the regex argument of s
calls in the replacement argument (using bash
here-string syntax (<<<
) for brevity):
$ sed -E 's/([.?!;:])_/_\1/g' <<<'On this _line,_ I show an example. !_'On this _line,_ I show an example. _!
\1
refers to the 1st capture group ((...)
) in the regex.
Note that -E
was used to enable support for extended regexes, which use modern syntax - both GNU sed
and BSD/macOS sed
support this option.
Generally, you don't need sed
's -e
option, unless you're passing the sed
script in multiple parts, in which case each part must be -e
-prefixed.
As for in-place updating of the input file:
-ie
probably does not do (exactly) what you want: while it does update the input file (by replacing it with a new file with updated content), it creates a backup file with suffix e
, because e
is interpreted as option -i
's option-argument.
If the intent is not to create a backup file, the syntax - sadly - differs based on what sed
implementation you're using:
GNU
sed
:sed -i ...
-i
must not be directly followed by any other options / characters.
BSD/macOS
sed
:sed -i '' ...
-i
must be followed by''
as the next, separate argument.
Here is one way you can do it with a single line:
sed 's/\([^\w\s]\)\(_\)/\2\1/g' test.txt
Essentially, you are looking for two characters, and swapping them.
s/ - This starts the substitution
\( \)
- This escapes the parentheses. Gotta do this, even if its ugly.
\s
a whitespace character
[ ]
sets up a character class
^
negates at the first position inside a character class
[^\w\s]
all characters that are not letters or whitespace (aka punctuation)
Then we get to the next match, an underscore. We make this the second item to check for
\(_\)
- First, find punctuation and mark that as match number 1, then find an underscore, right next to it, and mark it as match number 2.
/\2\1/
- Now, swap matches 1 and 2
/g
- do this globally.
The end. Now, you can output this to another file, or use another sed
modifier, (the -i
switch), to change the file inline.