0

I've lines of the following form

line="  this is a line with 2 leading spaces and a trailing control char^M"

I want to substitute both the 2 leading spaces and the trailing control char represented here by ^M with nothing.

echo "${line}" | sed 's/^[[:space:]]*//' | tr -dc '[:print:]'
echo "${line}" | sed 's/^[[:space:]]*//' | sed 's/[^[:print:]]//'

both works. I also tried with

echo "${line}" | sed 's/^[[:space:]]*|[^[:print:]]//'

but this doesn't work.

Why doesn't this last expression work?
How can I accomplish this with a single call to sed and a single regex?
What is the preferred solution, for example in terms of efficiency? Is it better to avoid many subshells?
Are there better solutions?

the_eraser
  • 381
  • 1
  • 3
  • 14
  • 4
    possible duplicate of [How to trim whitespace from bash variable?](http://stackoverflow.com/questions/369758/how-to-trim-whitespace-from-bash-variable) – ndnenkov Aug 16 '15 at 11:45
  • you are missing a colon in your expression(`:print`) + you need to escape the 'or' operator (`\|`) – Jiri Kremser Aug 16 '15 at 11:51
  • @ndn I read that post before asking and I don't think it is a duplicate since this question was intended to find a way to perform multiple substitution with a single sed call – the_eraser Sep 18 '15 at 11:05
  • @JiriKremser I've corrected the "[:print]" typo, thanks. Sorry to everyone for this long delay... – the_eraser Sep 18 '15 at 11:07

2 Answers2

2
sed 's/^[[:space:]]*|[^[:print]]//'

doesn't work because | matches itself literally. "Or" is spelled \| in sed. (And [:print] should be [:print:]).

But that's still not enough because by default sed only replaces the first occurrence; you need the /g flag to replace all occurrences:

sed 's/^[[:space:]]*\|[^[:print:]]//g'

But your original regex may have some unintended consequences: [[:space:]] matches newlines, so if the input is one or more complete lines, it will remove all blank lines, not just their contents. To prevent this, use [[:blank:]] instead:

sed 's/^[[:blank:]]*\|[^[:print:]]//g'
melpomene
  • 84,125
  • 8
  • 85
  • 148
0

This single sed should work:

sed 's/^[[:blank:]]*//; s/[[:cntrl:]]*$//' <<< "$line"
this is a line with 2 leading spaces and a trailing control char
anubhava
  • 761,203
  • 64
  • 569
  • 643