How to trim whitespace from a Bash variable?
Solution 1
A simple answer is:
echo " lol " | xargs
Xargs will do the trimming for you. It's one command/program, no parameters, returns the trimmed string, easy as that!
Note: this doesn't remove all internal spaces so "foo bar"
stays the same; it does NOT become "foobar"
. However, multiple spaces will be condensed to single spaces, so "foo bar"
will become "foo bar"
. In addition it doesn't remove end of lines characters.
Solution 2
Let's define a variable containing leading, trailing, and intermediate whitespace:
FOO=' test test test '
echo -e "FOO='${FOO}'"
# > FOO=' test test test '
echo -e "length(FOO)==${#FOO}"
# > length(FOO)==16
How to remove all whitespace (denoted by [:space:]
in tr
):
FOO=' test test test '
FOO_NO_WHITESPACE="$(echo -e "${FOO}" | tr -d '[:space:]')"
echo -e "FOO_NO_WHITESPACE='${FOO_NO_WHITESPACE}'"
# > FOO_NO_WHITESPACE='testtesttest'
echo -e "length(FOO_NO_WHITESPACE)==${#FOO_NO_WHITESPACE}"
# > length(FOO_NO_WHITESPACE)==12
How to remove leading whitespace only:
FOO=' test test test '
FOO_NO_LEAD_SPACE="$(echo -e "${FOO}" | sed -e 's/^[[:space:]]*//')"
echo -e "FOO_NO_LEAD_SPACE='${FOO_NO_LEAD_SPACE}'"
# > FOO_NO_LEAD_SPACE='test test test '
echo -e "length(FOO_NO_LEAD_SPACE)==${#FOO_NO_LEAD_SPACE}"
# > length(FOO_NO_LEAD_SPACE)==15
How to remove trailing whitespace only:
FOO=' test test test '
FOO_NO_TRAIL_SPACE="$(echo -e "${FOO}" | sed -e 's/[[:space:]]*$//')"
echo -e "FOO_NO_TRAIL_SPACE='${FOO_NO_TRAIL_SPACE}'"
# > FOO_NO_TRAIL_SPACE=' test test test'
echo -e "length(FOO_NO_TRAIL_SPACE)==${#FOO_NO_TRAIL_SPACE}"
# > length(FOO_NO_TRAIL_SPACE)==15
How to remove both leading and trailing spaces--chain the sed
s:
FOO=' test test test '
FOO_NO_EXTERNAL_SPACE="$(echo -e "${FOO}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"
echo -e "FOO_NO_EXTERNAL_SPACE='${FOO_NO_EXTERNAL_SPACE}'"
# > FOO_NO_EXTERNAL_SPACE='test test test'
echo -e "length(FOO_NO_EXTERNAL_SPACE)==${#FOO_NO_EXTERNAL_SPACE}"
# > length(FOO_NO_EXTERNAL_SPACE)==14
Alternatively, if your bash supports it, you can replace echo -e "${FOO}" | sed ...
with sed ... <<<${FOO}
, like so (for trailing whitespace):
FOO_NO_TRAIL_SPACE="$(sed -e 's/[[:space:]]*$//' <<<${FOO})"
Solution 3
There is a solution which only uses Bash built-ins called wildcards:
var=" abc "
# remove leading whitespace characters
var="${var#"${var%%[![:space:]]*}"}"
# remove trailing whitespace characters
var="${var%"${var##*[![:space:]]}"}"
printf '%s' "===$var==="
Here's the same wrapped in a function:
trim() {
local var="$*"
# remove leading whitespace characters
var="${var#"${var%%[![:space:]]*}"}"
# remove trailing whitespace characters
var="${var%"${var##*[![:space:]]}"}"
printf '%s' "$var"
}
You pass the string to be trimmed in quoted form. e.g.:
trim " abc "
A nice thing about this solution is that it will work with any POSIX-compliant shell.
Reference
Solution 4
Bash has a feature called parameter expansion, which, among other things, allows string replacement based on so-called patterns (patterns resemble regular expressions, but there are fundamental differences and limitations). [flussence's original line: Bash has regular expressions, but they're well-hidden:]
The following demonstrates how to remove all white space (even from the interior) from a variable value.
$ var='abc def'
$ echo "$var"
abc def
# Note: flussence's original expression was "${var/ /}", which only replaced the *first* space char., wherever it appeared.
$ echo -n "${var//[[:space:]]/}"
abcdef
Solution 5
In order to remove all the spaces from the beginning and the end of a string (including end of line characters):
echo $variable | xargs echo -n
This will remove duplicate spaces also:
echo " this string has a lot of spaces " | xargs echo -n
Produces: 'this string has a lot of spaces'

Theo Orphanos
Updated on April 12, 2022Comments
-
Theo Orphanos 9 months
I have a shell script with this code:
var=`hg st -R "$path"` if [ -n "$var" ]; then echo $var fi
But the conditional code always executes, because
hg st
always prints at least one newline character.- Is there a simple way to strip whitespace from
$var
(liketrim()
in PHP)?
or
- Is there a standard way of dealing with this issue?
I could use sed or AWK, but I'd like to think there is a more elegant solution to this problem.
-
Volomike about 10 yearsRelated, if you wanted to trim space on an integer and just get the integer, wrap with $(( $var )), and can even do that when inside double quotes. This became important when I used the date statement and with filenames.
-
user.friendly over 6 years"Is there a standard way of dealing with this issue?" Yes, use [[ instead of [.
$ var=$(echo)
$ [ -n $var ]; echo $? #undesired test return
0
$ [[ -n $var ]]; echo $?
1
-
Luis Alvarado over 6 yearsIf it helps, at least where am testing it on Ubuntu 16.04. Using the following matches trim in every way:
echo " This is a string of char " | xargs
. If you however have a single quote in the text you can do the following:echo " This i's a string of char " | xargs -0
. Note that I mention latest of xargs (4.6.0) -
Mecki over 5 yearsThe condition isn't true because of a newline as backticks swallow the last newline. This will print nothing
test=`echo`; if [ -n "$test" ]; then echo "Not empty"; fi
, this however willtest=`echo "a"`; if [ -n "$test" ]; then echo "Not empty"; fi
- so there must be more than just a newline at the end. -
Konstantin Burlachenko over 4 yearsA="123 4 5 6 "; B=
echo $A | sed -r 's/( )+//g'
; -
Jan Groth over 1 yearThis question would benefit from one of the answers being excepted.
- Is there a simple way to strip whitespace from
-
Theo Orphanos about 14 yearsI don't want to remove '\n' from the middle of the string, only from the beginning or end.
-
Paul Tomblin about 14 yearsOr rather, it works for spaces in the middle of a var, but not when I attempt to anchor it at the end.
-
Admin about 14 yearsDoes this help any? From the manpage: "${parameter/pattern/string} [...] If pattern begins with %, it must match at the end of the expanded value of parameter."
-
Paul Tomblin about 14 years@Ant, so they're not really regular expressions, but something similar?
-
Admin almost 14 yearsThey're regex, just a strange dialect.
-
Peter Lindqvist about 13 yearsto replace all matches echo ${var// }
-
rogerdpack over 12 yearsSweet that seems to work (ex:)
$stripped_version=
echo $var | awk '{gsub(/^ +| +$/,"")}1'`` -
dubiousjim almost 12 yearsYour second command should presumably have
##
not just#
. But in fact these don't work; the pattern you're giving matches a space followed by any sequence of other characters, not a sequence of 0 or more spaces. That*
is the shell globbing*
, not the usual "0-or-more" regexp*
. -
dubiousjim almost 12 yearsTerrific! I think this is the most lightweight and elegant solution.
-
glenn jackman over 11 yearsexcept awk isn't doing anything: echo'ing an unquoted variable has already stripped out whitespace
-
Nicholas Sushkin almost 11 yearsThat's not true. It's "echo" that removes whitespace, not the assignment. In your example, do
echo "$var"
to see the value with spaces. -
mklement0 over 10 yearsYou can easily avoid problems with non-default $IFS values by creating a local copy (which will go out of scope upon exiting the function):
trim() { local IFS=$' \t\n'; echo $1; }
-
Gilles 'SO- stop being evil' over 10 years
${var/ /}
removes the first space character.${var// /}
removes all space characters. There's no way to trim just leading and trailing whitespace with only this construct. -
mklement0 over 10 yearsSee @GuruM's post below for a similar, but more generic solution that (a) deals with all forms of white space and (b) also handles trailing white space.
-
mklement0 over 10 yearsIt is the unquoted use of
$xyz
withecho
that does the whitespace coalescing, not the variable assignment. To store the trimmed value in the variable in your example, you'd have to usexyz=$(echo -n $xyz)
. Also, this approach is subject to potentially unwanted pathname expansion (globbing). -
mklement0 over 10 years@PaulTomblin: the bash manual calls them patterns and while they share some features with regular expressions, they're sufficiently different to warrant not calling them regular expressions so as to avoid confusion.
-
Paul Tomblin over 10 yearsI think that was the point I was making - that flussence was calling them regular expressions, but they're not.
-
mklement0 over 10 yearsThis approach (a) also removes interior spaces and (b) only removes spaces, not other forms of white space.
-
mklement0 over 10 yearsThe first approach is tricky in that it not only normalizes interior whitespace (replaces all interior spans of whitespace with a single space each) , but is also subject to globbing (pathname expansion) so that, for instance, a
*
character in the input string would expand to all files and folders in the current working folder. Finally, if $IFS is set to a non-default value, trimming may not work (though that is easily remedied by addinglocal IFS=$' \t\n'
). Trimming is limited to the following forms of whitespace: spaces,\t
and\n
characters. -
mklement0 over 10 yearsThe second, regular expression-based approach is great and side effect-free, but in its present form is problematic: (a) on bash v3.2+, matching will by default NOT work, because the regular expression must be UNquoted in order to work and (b) the regular expression itself doesn't handle the case where the input string is a single, non-space character surrounded by spaces. To fix these problems, replace the
if
line with:if [[ "$trimmed" =~ ' '*([^ ]|[^ ].*[^ ])' '* ]]
. Finally, the approach only deals with spaces, not other forms of whitespace (see my next comment). -
mklement0 over 10 yearsThe function that utilizes regular expresssions only deals with spaces and not other forms of whitespace, but it's easy to generalize: Replace the
if
line with:[[ "$trimmed" =~ [[:space:]]*([^[:space:]]|[^[:space:]].*[^[:space:]])[[:space:]]* ]]
-
mklement0 over 10 yearsTo generalize the solution to handle all forms of whitespace, replace the space character in the
tr
andsed
commands with[[:space:]]
. Note that thesed
approach will only work on single-line input. For approaches that do work with multi-line input and also use bash's built-in features, see the answers by @bashfu and @GuruM. A generalized, inline version of @Nicholas Sushkin's solution would look like this:trimmed=$([[ " test test test " =~ [[:space:]]*([^[:space:]]|[^[:space:]].*[^[:space:]])[[:space:]]* ]]; echo -n "${BASH_REMATCH[1]}")
-
xebeche over 10 years@NicholasSushkin One could do
var=$(echo $var)
but I do not recommend it. Other solutions presented here are preferred. -
xebeche over 10 yearsAmazing! Simple and effective! Clearly my favorite solution. Thank you!
-
GuruM over 10 yearsas you've observed trim() removes leading and trailing whitespace only.
-
Ярослав Рахматуллин over 10 years@luca borrione: local var="$1"
-
GuruM over 10 yearsAs mkelement has already noted you need to pass the function parameter as a quoted string i.e. $(trim "$string") instead of $(trim $string). I've updated the code to show the correct usage. Thanks.
-
GuruM over 10 yearsNote: As suggested by @mkelement it will not work for multi-line string though it should work for single-line strings.
-
Luca Borrione over 10 yearsYou are wrong: it does work on multi-line strings too. Just test it out!:)
-
GuruM over 10 years+1 for the usage - made it easy for me to test out the code. However the code still won't work for multi-line strings. If you look carefully at the output, you'll notice that any leading/trailing internal spaces are also getting removed e.g. the space in front of " multi-line" is replaced by "multi-line". Just try increasing the number of leading/trailing spaces on each line.
-
GuruM over 10 yearsI tried your solution but using local var="[email protected]" compresses multiple internal-spaces into a single space. So a string with multiple-space like " a<multi-space>b c d " would translate to single-spaced "a b c d". The only way as suggested by @mkelement is to quote the input variable directly i.e. trim "$string" in which case [email protected] expands to a single parameter anyway.
-
Luca Borrione over 10 yearsNow I see what you mean! Thank you for the head up, I edited my answer.
-
GuruM over 10 years@"Luca Borrione" - welcome :-) Would you explain the sed syntax you're using in trim()? It might also help any user of your code to tweak it to other uses. Also it might even help find edge-cases for the regular-expression.
-
GuruM over 10 years
-
GuruM over 10 years@mkelement +1 for taking the trouble to rewrite my code snippet as a function. Thanks
-
Will almost 10 yearsNice. This works really well. I have decided to pipe it to
xargs echo
just to be verbose about what i'm doing, but xargs on its own will use echo by default. -
instanceof me almost 10 yearsIf you do that often, appending
alias trim="sed -e 's/^[[:space:]]*//g' -e 's/[[:space:]]*\$//g'"
to your~/.profile
allows you to useecho $SOMEVAR | trim
andcat somefile | trim
. -
joshlf over 9 yearsThat won't work if there are more than one space in between any two words. Try:
echo $(echo "1 2 3")
(with two spaces between 1, 2, and 3). -
n611x007 about 9 yearsOn Windows this is a very good solution. I usually use gnu utils binaries without bash (eg. cygwin, unxutils, custom builds, mingw, git for windows, gnuwin32...) and
sed
andawk
support is not very consistent across these. -
n611x007 about 9 yearsAlso, both
sed
,awk
andbash
are tools so old that they use a syntax that can feel "arcane". People who are not often using them, wanting to do a simple string manipulation, would easily feel overwhelmed by'
or"
or \ or/
or//
or^
or$
, asking themselves just which one was it? Can't believe there is no more straightforward solution to this simple thing... There is. -
n611x007 about 9 yearsAn other reason for using
xargs
is why introduce dependency? xargs is a binary that can be used with other shells (I even managed to use it withcmd.exe
). Since it's quite straightforward it doesn't depend on any learning curve as a tool for being immediately useful either. -
Asclepius about 9 yearsUsing
grep .
can further prevent the output of empty lines. -
Jocelyn delalande about 9 yearsNice trick, but be carefull, you can use it for one-line string but −by xargs design− it will not just do triming with multi-line piped content. sed is your friend then.
-
Nick about 9 yearsThis doesn't trim whitespace from the front and back - it removes all whitespace from the string.
-
Evgeni Sergeev about 9 yearsThis collapses multiple contiguous spaces into one.
-
Victor Zamanian almost 9 yearsI wrote a
sed
solution that only uses a single expression rather than two:sed -r 's/^\s*(\S+(\s+\S+)*)\s*$/\1/'
. It trims leading and trailing whitespace, and captures any whitespace-separated sequences of non-whitespace characters in the middle. Enjoy! -
Torben over 8 years@VictorZamanian Your solution does not work if the input contains only whitespace. The two-pattern sed solutions given by MattyV and instanceof me work fine with whitespace only input.
-
Victor Zamanian over 8 years@Torben Fair point. I suppose the single expression could be made conditional, with
|
, so as to keep it as one single expression, rather than several. -
gniourf_gniourf over 8 yearsDid you try it when
foo
contains a wildcard? e.g.,foo=" I * have a wild card"
... surprise! Moreover this collapses several contiguous spaces into one. -
Joe over 8 yearsThis will trim only 1 space character. So the echo results in
'hello world ', 'foo bar', 'both sides '
-
Mark G. about 8 yearsClever! This is my favorite solution as it uses built-in bash functionality. Thanks for posting! @San, it's two nested string trims. E.g.,
s=" 1 2 3 "; echo \""${s%1 2 3 }"\"
would trim everything from the end, returning the leading" "
. Subbing1 2 3
with[![:space:]]*
tells it to "find the first non-space character, then clobber it and everything after". Using%%
instead of%
makes the trim-from-end operation greedy. This is nested in a non-greedy trim-from-start, so in effect, you trim" "
from the start. Then, swap %, #, and * for the end spaces. Bam! -
Admin almost 8 yearsThe only problem with xargs is that it will introduce a newline, if you want to keep the newline off I would recommend
sed 's/ *$//'
as an alternative. You can see thexargs
newline like this:echo -n "hey thiss " | xargs | hexdump
you will notice0a73
thea
is the newline. If you do the same withsed
:echo -n "hey thiss " | sed 's/ *$//' | hexdump
you will see0073
, no newline. -
bos almost 8 yearsCareful; this will break hard if the string to xargs contains surplus spaces in between. Like " this is one argument ". xargs will divide into four.
-
Sasha almost 8 yearsThis is bad. 1. It will turn
a<space><space>b
intoa<space>b
. 2. Even more: it will turna"b"c'd'e
intoabcde
. 3. Even more: it will fail ona"b
, etc. -
Daniel Alder almost 8 years@makevoid Why did you remove the (very important) warning from this answer? This doesn't change the behaviour of
xargs
... -
J.D. almost 8 yearsThese are useful if you know there will be no spaces in the string. They work great for converting
" foo "
to"foo"
. For" hello world "
, not so much. -
makevoid over 7 years@DanielAlder added the note, I removed that because it was too long, notes have to be short - a too long answer can be considered wrong sometimes because of TL;DR :)
-
Aquarius Power over 7 yearsvery ingenious, as it is also extremely an "one liner" helper
read -rd '' str < <(echo "$str")
thx! -
Aquarius Power over 7 years@CraigMcQueen it is the variable value, as
read
will store at variable by its name $1 a trimmed version of its value ${!1} -
pdwalker over 7 yearswhile that works, you may want to consider offering a solution that does not involve launching a full python interpreter just to trim a string. It's just wasteful.
-
flabdablet over 7 yearsThe trim() function's parameter is a variable name: see the call to trim() inside test_trim(). Within trim() as called from test_trim(), $1 expands to foo and ${!1} expands to $foo (that is, to the current contents of variable foo). Search the bash manual for 'variable indirection'.
-
Quinn Comendant over 7 yearsI've been using xargs to trim simple strings until I discovered it fails on strings with a single quote or multiple internal spaces (as was warned above). I can't recommend this method.
-
caesarsol over 7 yearsthis is jut wrong, the value in the
xyz
variable is NOT trimmed. -
farid99 over 7 yearscould you explain the syntax for
sed
? -
Paul Tomblin over 7 yearsThe regular expression matches all trailing whitespace and replaces it with nothing.
-
Admin over 7 yearsThe line
echo -e "${FOO}" | wc -m
counts one more character because echo adds it. Tryecho -ne "${FOO}" | wc -m
and get the correct count. -
musicin3d about 7 yearsDidn't work for me. The first one printed an untrimmed string. The second threw bad substitution. Can you explain what's going on here?
-
musicin3d about 7 yearsThis is an excellent solution if you: 1. want no spaces on the ends 2. want only one space between each word 3. are working with a controlled input with no wildcards. It essentially turns a badly formatted list into a good one.
-
gMale about 7 years@musicin3d : this is a site I use frequently that spells out how variable manipulation works in bash search for
${var##Pattern}
for more details. Also, this site explains bash patterns. So the##
means remove the given pattern from the front and%%
means remove the given pattern from the back. The+( )
portion is the pattern and it means "one or more occurrence of a space" -
Qian Chen almost 7 yearsHow about leading whitespaces?
-
DrBeco almost 7 yearsFunny, it worked in the prompt, but not after transposing to the bash script file.
-
DrBeco almost 7 yearsGood reminder of the wildcards @gniourf_gniourf +1. Still an excelente solution, Vamp. +1 to you too.
-
gMale almost 7 yearsweird. Is it the same bash version in both instances?
-
F-3000 over 6 yearsThis is a very quick solution when trimming simple single-word strings. I used this to strip sqlite's -line output, where the column name has useless padding script-wise.
-
Craig over 6 yearsThis strips all trailing whitespace
sed -e 's/\s*$//'
. Explanation: 's' means search, the '\s' means all whitespace, the '*' means zero or many, the '$' means till the end of the line and '//' means substitute all matches with an empty string. -
vinc17 over 6 yearsAn inconvenient of this method is that it uses
sed
, whose behavior depends on the system. In particular,sed
from Solaris 10 doesn't support[[:space:]]
. -
vinc17 over 6 yearsI haven't found any unwanted side effects, and the main code works with other POSIX-like shells too. However, under Solaris 10, it doesn't work with
/bin/sh
(only with/usr/xpg4/bin/sh
, but this is not what will be used with usual sh scripts). -
vinc17 over 6 yearsWell, let's say that this is also OK for Solaris 10 even without bash, where one can put
{ a=a; : ${a%b}; } 2> /dev/null || exec /usr/xpg4/bin/sh -- "$0" ${1+"[email protected]"}
at the beginning of the script to use a compatible shell. -
Gene Pavlovsky over 6 yearsMuch better solution than using sed, tr etc., since it's much faster, avoiding any fork(). On Cygwin difference in speed is orders of magnitude.
-
Gene Pavlovsky over 6 yearsHow about this little modification, to support trimming multiple vars in one call?
trim() { while [[ $# -gt 0 ]]; do read -rd '' $1 <<<"${!1}"; shift; done; }
-
flabdablet over 6 years@AquariusPower there's no need to use echo in a subshell for the one-liner version, just
read -rd '' str <<<"$str"
will do. -
Nils about 6 yearsBah in C this would be way simpler to implement!
-
Daniel Alder about 6 yearsSure. Unfortunately, this is not C and sometimes you want to avoid calling external tools
-
sehe about 6 yearsAs much as I appreciate knowing about the shell options, I don't think the end result is more elegant than simply doing 2 pattern substitutions
-
Leon S. almost 6 yearsTo make the code both more readable and copy-past compatible, you could change the brackets to escaped characters:
[\ \t]
-
Ohad Schneider almost 6 years@San At first I was stumped because I thought these were regular expressions. They are not. Rather, this is Pattern Matching syntax (gnu.org/software/bash/manual/html_node/Pattern-Matching.html, wiki.bash-hackers.org/syntax/pattern) used in Substring Removal (tldp.org/LDP/abs/html/string-manipulation.html). So
${var%%[![:space:]]*}
says "remove fromvar
its longest substring that starts with a non-space character". That means you are left only with the leading space(s), which you subsequently remove with${var#..
. The following line (trailing) is the opposite. -
Mig82 almost 6 yearsI was very confused by the -e option of the echo command. I'm working on a Mac and it's not recognised. Or at least not documented in the man page.
FOO=' test test test ' FOO_NO_WHITESPACE=$(echo "${FOO}" | tr -d '[:space:]')
works fine for me. -
Ville almost 6 years@mklement0 Sometimes that's exactly what is needed, though! :-)
-
mklement0 almost 6 years@Ville: Yes, and with the help of my behavior-clarifying comment future readers can decide if this solution is the right one for them.
-
rkachach almost 6 yearsBasically the xargs removes all the delimiters from the string. By default it uses the space as delimiter (this could be changed by the -d option).
-
Ron Burk over 5 yearsSurely preferable to, for example (ye gods!), shelling out to Python. Except I think it's simpler and more general to correctly handle string that contains only spaces.Slightly simplified expression would be:
^[[:space:]]*(.*[^[:space:]])?[[:space:]]*$
-
nwinkler over 5 yearsI understand the downsides of this, but it's great for when you know the expected output is going to be just one value, e.g. from
wc -l
. I use this for removing leading spaces (which seem to be included by the macOS version ofwc
):ls .. | wc -l | xargs
-
makevoid over 5 years@AlexanderMills thanks for the sincerity.... maybe try with this?
A=$(echo " lol " | xargs); echo $A
-
Potherca over 5 yearsThis is by far the cleanest (both short and readable) solution.
-
wjandrea about 5 years@Joe I added a better option.
-
Clint Pachl almost 5 yearsWorks with OpenBSD's default /bin/ksh as well.
/bin/sh -o posix
works too but I'm suspicious. -
catpnosis over 4 years
t=" "" a "" "; echo "=${t#* }="
output= a =
leading multiple spaces are not stripped.t=" "" a "" "; echo "=${t%% *}="
output==
trailing spaces are stripped with string content. (Double quoting because of SE.) -
Abhijit Sarkar over 4 yearsNot a bash wizard here; what's
trimmed
? Is it a built-in thing or the variable that is being trimmed? -
Armali over 4 years@Abhijit Sarkar - It's the latter.
-
Cecil Curry over 4 yearsThis is overwhelmingly the ideal solution. Forking one or more external processes (e.g.,
awk
,sed
,tr
,xargs
) merely to trim whitespace from a single string is fundamentally insane – particularly when most shells (including bash) already provide native string munging facilities out-of-the-box. -
Cecil Curry over 4 yearsBash patterns are not regular expressions. Bash supports both Bash pattern syntax and genuine regular expressions (e.g., via the builtin
=~
operator introduced with Bash 3.0.0). The two have nothing to do with one another. -
scai about 4 yearsNote that
tr -d "[:space:]"
removes both horizontal and vertical whitespace characters (=newlines). To remove just horizontal whitespace characters simply usetr -d " "
. -
bfontaine almost 4 yearsWhy do you need
echo -n
at all?echo " my string " | xargs
has the same output. -
rkachach almost 4 yearsecho -n removes the end of line as well
-
Maëlan over 3 yearsBash “patterns” are regular expressions, only with a different syntax than “POSIX (extended) regular expressions”. You are right in saying that they are incompatible, and that Bash expects them in different places (the former in parameter substitutions, the latter after the
=~
operator). As for their expressiveness: with “extended pattern matching operators” (shell optionextglob
), the only features that POSIX regexps have and Bash patterns lack, are^
and$
(compareman bash
§ “Pattern Matching” withman 7 regex
). -
Maëlan over 3 yearsNote that (with a recent enough version of Bash?), you can simplify the mechanism for restoring the option
extglob
, by usingshopt -p
: simply writelocal restore="$(shopt -p extglob)" ; shopt -s extglob
at the beginning of your function, andeval "$restore"
at the end (except, granted, eval is evil…). -
Ken Ingram over 3 yearsThis was an excellent solution. Just what I was looking for. To use the built-ins. Now I just need the codebook to decipher all of it. Is this solution based on years of experience? I didn't know how BASH could do this, but I had a feeling it should be able to do it.
-
akhan over 3 yearsWhat is the need for nested double quotes? Seems to work without inner pair.
-
Sasha over 3 years@makevoid, as for "added the note", the note you've added is very different from the previous warning. The previous warning said that this approach changes inner spaces (I'd better say: ruins them). While your note just says that the inner spaces wouldn't be fully removed (almost the opposite thing).
-
Isaac Freeman over 3 yearsWouldn't it be easier to just
var=${var##+([[:space:]])}
andvar=${var%%+([[:space:]])}
? The bash pattern+(...)
means one or more of whatever is in the parens. That way you don't have to do the weird double-expansion. -
Isaac Freeman over 3 yearsOh, and I guess the solution in my last comment requires
shopt -s extglob
. -
Victor Sergienko over 3 yearsTo continuously trim all stdin lines, run it through
xargs -l
. -
vaab over 3 yearsHere's a subtle bug with your current implementation using
echo
happening at least in bash: try to trim the following string: "-e", it'll output nothing and not the expected string "-e". Indeed, this will end launchingecho -n -e
which outputs nothing. I would suggestprintf "%s" "$var"
to replace your final instruction. -
POMATu about 3 yearsthis is bad, it removes backslash from string
-
Admin about 3 yearsyou are a hero. much easier then
perl/sed/bashism
-
miguelmorin about 3 years@CecilCurry Getting the result of
trim
into a variable would still require command substitution and a subshell, e.g.var=$(trim " abc ")
, so in a shell script the advantage over piping is minimal, right? -
Kaii almost 3 yearsthis is misuse.
xargs
is made for another purpose and might change trimming behaviour anytime. it's bad advice to use this for trimming. As @Sasha already pointed out: it already has some weird behaviours you would not expect when trimming strings! -
Harlin almost 3 yearsBumped you to 1000 since it had been sitting at 999 for some time :-D
-
Admin almost 3 yearsbash is evil lulz for requiring so long an answer to "how to trim whitespace" isn't there some coreutils program that can do this? xargs is one I guess but not explicitly made for that.
-
Brent212 almost 3 yearsIn 's/ *$//', why are there 2 spaces before the asterisk, instead of a single space? Is that a typo?
-
Paul Tomblin almost 3 years@Brent212 because you don't want to match unless there is at least one space.
's/ +$//'
might work as well. -
Brent212 almost 3 years@PaulTomblin sure, I get that we only want to match one or more spaces, but wouldn't 's/ *$//' do the trick, instead of 's/ *$//' ? The later seems like it'd only match two or more spaces.
-
Paul Tomblin almost 3 yearsYou’re thinking of glob, not regex. * means 0 or more of the previous thing, so s/ *$// will match on zero spaces.
-
JPT over 2 yearsdownvote because this doesn't give any explanation. it doesn't work for me and I just don't know why (need \r\n removed that was added by recent winepath)
-
Dima Korobskiy over 2 yearsGreat solution! One potential improvement: it looks like
[[:space:]]
could be replaced with, well, a space:${var##+( )}
and${var%%+( )}
work as well and they are easier to read. -
Daniel Alder over 2 years@leondepeon did you try this? I tried when i wrote it and tried again, and your suggestion doesn't work in any of bash, dash, busybox
-
Leon S. over 2 years@DanielAlder I did, but as it is already 3 years ago, I can't find the code where I used it. Now however, I'd probably use
[[:space:]]
like in one of the other answers: stackoverflow.com/a/3352015/3968618 -
Michał Górny over 2 yearsWhile using builtin functionality seems nice, extglob is very slow in my experience.
-
JL Peyret over 2 yearsFWIW,
var="${var//[[:space:]]/}"
works fine in re-assigning the trimmed contents back to the original variable. -
Daniel Alder about 2 years@DrBeco
#!/bin/sh
is not necessarily bash ;) -
DrBeco about 2 yearsHi @DanielAlder, you replied to a comment from 2016, and I have no idea what is this about. But I agree with you. Have a good one.
-
Kévin Berthommier about 2 years
xargs <<< " test teste grdgdft"
-
David Scott Kirby almost 2 yearsIt takes lots of examples because trimming a whitespace is about as easy as trimming your own hair.
-
David Scott Kirby almost 2 yearsExcept in this world it's easier to trim the back, you can barely see the top, and your clippers behave wildly differently depending on where you use them.
-
Sumit Trehan almost 2 yearsThe cleanest solution
-
mc2 over 1 yearI've tried your solution, but it fails with non-breaking space at the end (en.wikipedia.org/wiki/Non-breaking_space). Do you have any idea how to improve your solution to U+00A0 character?
-
Alek over 1 year@akhan, Yes, quotes are NOT needed in variable assignment in BASH: stackoverflow.com/questions/3958681/… unix.stackexchange.com/questions/97560/…
-
Ярослав Рахматуллин over 1 year@DrBeco It's really easy to remember what this is about, just check the title of the original question and the answer these comments are under. Btw, it didn't work for you because your bash hell did not have the option
shopt -s extglob
. I updated the answer. -
andrew lorien over 1 yearThis helped me, but the question specifically asked about a trailing newlin which this does not remove.
-
AngryDane over 1 yearI tried two other solution from this question/answer page and only this one worked as expected, keep-it-simple-silly strikes again!!
-
Sridhar Sarnobat over 1 yearYou could even use process command substitution but I guess that won't work for Bourne Shell
-
Faither over 1 yearRelated to @mklement0 coment: mywiki.wooledge.org/IFS.
The default value of IFS is space, tab, newline. (A three-character string.)
... -
Zane over 1 yearGreat. Thanks for the function - added to my local library of valuabe functions.
-
black.swordsman over 1 yearThis answer doesn't remove \r or CR from the end of a variable.
-
ardnew about 1 yearYou can add support for piped input, stdin, etc. with a single line addition. After the line
local var="$*"
, add a new line(( $# )) || read -re var
. Now this function can be called as inecho " hello " | trim
to produce justhello
. -
uli42 11 monthswill not work if the_string contains wildcards, e.g. "the_string=" foo * bar "
-
bobbogo 9 monthsThat formulation for fewer lines is wrong. You can't do
${${f}}
in bash.