1

my current kind of unsolved problem with bash is how to replace all the characters in the [:punct:] class, that is

[!"#$%&'()*+,\-./:;<=>?@[\\\]^_`{|}~]

, each with the same character escaped by a backslash. For example, I want ^h?e.l*l+o: to become \^h\?e\.l\*l\+o\:.

I can do it in a multi-liner fashion with loops. Is it possible to do it in a more succint and elegant way?

Thanks, Luca

the_eraser
  • 381
  • 1
  • 3
  • 14
  • Are you sure you need to escape *all* punctuation, or just ones that have special meaning in some context? What's the use case? (There may be various simple alternatives depending on exactly *why* they need to be escaped.) – chepner Sep 18 '15 at 12:24
  • Does [this question](https://stackoverflow.com/questions/29613304/is-it-possible-to-escape-regex-metacharacters-reliably-with-sed) help any? – Etan Reisner Sep 18 '15 at 13:25
  • @chepner You may be right. I tried to escape all punctuation just for simplicity, but I have a problem with the apostrophe ' (and maybe some other characters that I haven't tested yet) that doesn't match anymore with itself if escaped. I basically want to escape regex and glob metacharacters. The simplest solution is to remove them as in `[!#$%&()*+,\-./:;<=>?@[\\\]^_{|}~]`. Is there any other approach? – the_eraser Sep 19 '15 at 09:21
  • Yes, there are many other approaches as in the post quoted by @EtanReisner two comments above. Thanks, I've learned a lot. – the_eraser Sep 20 '15 at 14:28

1 Answers1

5

Can you use sed?

echo '^h?e.l*l+o:' | sed 's/\([[:punct:]]\)/\\\1/g'

Without sed, I can't think of anything else than looping over the characters:

s='^h?e.l*l+o:'
o=''
for ((i=0; i<${#s}; i++)) ; do
    c=${s:i:1}
    [[ $c =~ [[:punct:]] ]] && o+=\\
    o+=$c
done
echo "$o"

Another possibility is to use Perl's quotemeta:

echo '^h?e.l*l+o:' | perl -lne 'print quotemeta'

-l handles newlines. -n process the input line by line.

choroba
  • 231,213
  • 25
  • 204
  • 289