I'd like to use bash to replace multiple adjacent spaces in a string by a single space. Example:
Original string:
"too many spaces."
Transformed string:
"too many spaces."
I've tried things like "${str//*( )/.}"
or awk '{gsub(/[:blank:]/," ")}1'
but I can't get it right.
Note: I was able to make it work with <CMD_THAT_GENERATES_THE_INPUT_STRINGH> | perl -lpe's/\s+/ /g'
but I had to use perl to do the job. I'd like to use some bash internal syntax instead of calling an external program, if that is possible.
Continuing with that same thought, if your string with spaces is already stored in a variable, you can simply use echo unquoted within command substitution to have bash remove the additional whitespace for your, e.g. $ foo="too many spaces."; bar=$(echo $foo); echo "$bar" too many spaces.
The metacharacter “\s” matches spaces and + indicates the occurrence of the spaces one or more times, therefore, the regular expression \S+ matches all the space characters (single or multiple). Therefore, to replace multiple spaces with a single space.
Answer: Use the JavaScript replace() method.
You can enable shopt -s extglob and then just use NEWHEAD=${NEWHAED/+( )/ } to remove internal spaces.
Using tr
:
$ echo "too many spaces." | tr -s ' '
too many spaces
man tr
:
-s, --squeeze-repeats
replace each sequence of a repeated character that is listed in
the last specified SET, with a single occurrence of that charac‐
ter
Edit: Oh, by the way:
$ s="foo bar"
$ echo $s
foo bar
$ echo "$s"
foo bar
Edit 2: On the performance:
$ shopt -s extglob
$ s=$(for i in {1..100} ; do echo -n "word " ; done) # 100 times: word word word...
$ time echo "${s//+([[:blank:]])/ }" > /dev/null
real 0m7.296s
user 0m7.292s
sys 0m0.000s
$ time echo "$s" | tr -s ' ' >/dev/null
real 0m0.002s
user 0m0.000s
sys 0m0.000s
Over 7 seconds?! How is that even possible. Well, this mini laptop is from 2014 but still. Then again:
$ time echo "${s//+( )/ }" > /dev/null
real 0m1.198s
user 0m1.192s
sys 0m0.000s
Here is a way to do this using pure bash
and extglob
:
s="too many spaces."
shopt -s extglob
echo "${s//+([[:blank:]])/ }"
too many spaces.
[[:blank:]]
matches a space or tab character+([[:blank:]])
matches one or more of the bracket expression (requires extglob
)If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With