0

How to remove all words between two special chars using sed? Note that the original line has to be in the result aswell.

Current code:

echo 'a "removeme" b +removeme+ c *removeme#d+removeme~ .123' | sed -r '/\W/ p; s/\W[^\W]*\W//g'

Result:

a "removeme" b +removeme+ c *removeme#d+removeme~ .123
a123

Expected result:

a "removeme" b +removeme+ c *removeme#d+removeme~ .123
a  b  c d .123
4
  • You would need "reluctant" matching that doesn't exist in sed. See here for alternatives.
    – xenoid
    Nov 18, 2019 at 10:13
  • #d+ will be also removed due to the rule words between special chars - it won't be in the result Nov 18, 2019 at 10:18
  • If *removeme# is removed, the next "pair" of special chars would be + and ~ and everything between and including should be removed.
    – GioWay
    Nov 18, 2019 at 10:28
  • What counts as a "special char"? Is it merely non-alphanumeric? Nov 18, 2019 at 13:37

3 Answers 3

1

In your very special case, you can:

  • replace all the unwanted characters by a single known character (whihc is part of that set)
  • delete all the strings between two instances of that replacement character
echo 'a "removeme" b +removeme+ c *removeme#d+removeme~ .123' | sed -e '/\W/p; s/["+*#~]/#/g ; s/#[^#]\+#//g'
a "removeme" b +removeme+ c *removeme#d+removeme~ .123
a  b  c d .123

Note that since you want to keep the ., you cannot use 'non-word' class since these include the '.'. If you want to avoid giving an explicit list of characters at all costs you can:

  • replace the dot by a word character that you aren't likely to encounter (thorn, slashed O, accented a/e/i/o/u, or greek/cyrillic)
  • apply the expression above using [:punct:]
  • reinstate the dot.
2
  • This works for the case above, but if the input is "aaaa#x# bbb.123", the new line in the output is "aaaa bbb@123" so it replaces the dot with @, which generates a new line that I do not want to have. Instead I want to keep the dot from the input. Sorry for being not clear enough, the post has been edited.
    – GioWay
    Nov 18, 2019 at 10:56
  • You can replace the [:punct:] with an explicit list of characters. Note that in your own code, \W would also match a ..
    – xenoid
    Nov 18, 2019 at 11:02
0

Change all dots to newlines, guaranteed to not be present AND ensures a non punctuation char as well. Then it's a simple matter of non greedy matching between two punctuation chars:

$  echo 'a "removeme" b +removeme+ c *removeme#d+removeme~ .123' |
   sed -e 'p
     y/./\n/
     s/[[:punct:]][^[:punct:]]*[[:punct:]]//g
     y/\n/./
   '

a "removeme" b +removeme+ c *removeme#d+removeme~ .123
a  b  c d .123

Note: this is all within Posix sed.

0

Perl is skillful at handling such cases. We use negative lookahead to create a category of punctuation chars excluding the dot :

echo '......' |
perl -lpe '
 print;
 $p = qr/(?!\.)[[:punct:]]/;
 s/$p.*?$p//g;
' 

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .