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 about 2 years
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 over 11 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 about 8 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 almost 8 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 almost 7 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 almost 6 yearsA="123 4 5 6 "; B=
echo $A | sed -r 's/( )+//g'
; -
Jan Groth almost 3 yearsThis question would benefit from one of the answers being excepted.
- Is there a simple way to strip whitespace from
-
Theo Orphanos over 15 yearsI don't want to remove '\n' from the middle of the string, only from the beginning or end.
-
Paul Tomblin over 15 yearsOr rather, it works for spaces in the middle of a var, but not when I attempt to anchor it at the end.
-
Admin over 15 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 over 15 years@Ant, so they're not really regular expressions, but something similar?
-
Admin about 15 yearsThey're regex, just a strange dialect.
-
Peter Lindqvist over 14 yearsto replace all matches echo ${var// }
-
rogerdpack about 14 yearsSweet that seems to work (ex:)
$stripped_version=
echo $var | awk '{gsub(/^ +| +$/,"")}1'`` -
dubiousjim over 13 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 over 13 yearsTerrific! I think this is the most lightweight and elegant solution.
-
glenn jackman almost 13 yearsexcept awk isn't doing anything: echo'ing an unquoted variable has already stripped out whitespace
-
Nicholas Sushkin about 12 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 almost 12 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' almost 12 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 almost 12 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 almost 12 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 almost 12 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 almost 12 yearsI think that was the point I was making - that flussence was calling them regular expressions, but they're not.
-
mklement0 almost 12 yearsThis approach (a) also removes interior spaces and (b) only removes spaces, not other forms of white space.
-
mklement0 almost 12 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 almost 12 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 almost 12 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 almost 12 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 11 years@NicholasSushkin One could do
var=$(echo $var)
but I do not recommend it. Other solutions presented here are preferred. -
xebeche over 11 yearsAmazing! Simple and effective! Clearly my favorite solution. Thank you!
-
GuruM over 11 yearsas you've observed trim() removes leading and trailing whitespace only.
-
Ярослав Рахматуллин over 11 years@luca borrione: local var="$1"
-
GuruM over 11 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 11 yearsNote: As suggested by @mkelement it will not work for multi-line string though it should work for single-line strings.
-
Luca Borrione over 11 yearsYou are wrong: it does work on multi-line strings too. Just test it out!:)
-
GuruM over 11 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 11 yearsI tried your solution but using local var="$@" 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 $@ expands to a single parameter anyway.
-
Luca Borrione over 11 yearsNow I see what you mean! Thank you for the head up, I edited my answer.
-
GuruM over 11 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 11 years
-
GuruM over 11 years@mkelement +1 for taking the trouble to rewrite my code snippet as a function. Thanks
-
Will about 11 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 about 11 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 10 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 over 10 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 over 10 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 over 10 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 over 10 yearsUsing
grep .
can further prevent the output of empty lines. -
Jocelyn delalande over 10 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 over 10 yearsThis doesn't trim whitespace from the front and back - it removes all whitespace from the string.
-
Evgeni Sergeev over 10 yearsThis collapses multiple contiguous spaces into one.
-
Victor Zamanian about 10 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 about 10 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 about 10 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 about 10 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 almost 10 yearsThis will trim only 1 space character. So the echo results in
'hello world ', 'foo bar', 'both sides '
-
Mark G. over 9 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 over 9 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 over 9 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 about 9 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 about 9 years@makevoid Why did you remove the (very important) warning from this answer? This doesn't change the behaviour of
xargs
... -
J.D. about 9 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 about 9 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 about 9 yearsvery ingenious, as it is also extremely an "one liner" helper
read -rd '' str < <(echo "$str")
thx! -
Aquarius Power about 9 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 about 9 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 about 9 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 almost 9 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 almost 9 yearsthis is jut wrong, the value in the
xyz
variable is NOT trimmed. -
farid99 almost 9 yearscould you explain the syntax for
sed
? -
Paul Tomblin almost 9 yearsThe regular expression matches all trailing whitespace and replaces it with nothing.
-
Admin almost 9 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 over 8 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 over 8 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 over 8 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 about 8 yearsHow about leading whitespaces?
-
DrBeco about 8 yearsFunny, it worked in the prompt, but not after transposing to the bash script file.
-
DrBeco about 8 yearsGood reminder of the wildcards @gniourf_gniourf +1. Still an excelente solution, Vamp. +1 to you too.
-
gMale about 8 yearsweird. Is it the same bash version in both instances?
-
F-3000 about 8 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 about 8 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 about 8 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 about 8 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 about 8 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+"$@"}
at the beginning of the script to use a compatible shell. -
Gene Pavlovsky almost 8 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 almost 8 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 almost 8 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 over 7 yearsBah in C this would be way simpler to implement!
-
Daniel Alder over 7 yearsSure. Unfortunately, this is not C and sometimes you want to avoid calling external tools
-
sehe over 7 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. over 7 yearsTo make the code both more readable and copy-past compatible, you could change the brackets to escaped characters:
[\ \t]
-
Ohad Schneider over 7 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 about 7 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 about 7 years@mklement0 Sometimes that's exactly what is needed, though! :-)
-
mklement0 about 7 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 about 7 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 about 7 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 almost 7 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 almost 7 years@AlexanderMills thanks for the sincerity.... maybe try with this?
A=$(echo " lol " | xargs); echo $A
-
Potherca over 6 yearsThis is by far the cleanest (both short and readable) solution.
-
wjandrea over 6 years@Joe I added a better option.
-
Clint Pachl about 6 yearsWorks with OpenBSD's default /bin/ksh as well.
/bin/sh -o posix
works too but I'm suspicious. -
catpnosis about 6 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 about 6 yearsNot a bash wizard here; what's
trimmed
? Is it a built-in thing or the variable that is being trimmed? -
Armali almost 6 years@Abhijit Sarkar - It's the latter.
-
Cecil Curry over 5 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 5 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 over 5 yearsNote that
tr -d "[:space:]"
removes both horizontal and vertical whitespace characters (=newlines). To remove just horizontal whitespace characters simply usetr -d " "
. -
bfontaine about 5 yearsWhy do you need
echo -n
at all?echo " my string " | xargs
has the same output. -
rkachach about 5 yearsecho -n removes the end of line as well
-
Maëlan about 5 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 about 5 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 about 5 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 almost 5 yearsWhat is the need for nested double quotes? Seems to work without inner pair.
-
Sasha almost 5 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 4 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 4 yearsOh, and I guess the solution in my last comment requires
shopt -s extglob
. -
Victor Sergienko over 4 yearsTo continuously trim all stdin lines, run it through
xargs -l
. -
vaab over 4 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 over 4 yearsthis is bad, it removes backslash from string
-
Admin over 4 yearsyou are a hero. much easier then
perl/sed/bashism
-
miguelmorin over 4 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 about 4 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 about 4 yearsBumped you to 1000 since it had been sitting at 999 for some time :-D
-
Admin about 4 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 about 4 yearsIn 's/ *$//', why are there 2 spaces before the asterisk, instead of a single space? Is that a typo?
-
Paul Tomblin about 4 years@Brent212 because you don't want to match unless there is at least one space.
's/ +$//'
might work as well. -
Brent212 about 4 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 about 4 yearsYou’re thinking of glob, not regex. * means 0 or more of the previous thing, so s/ *$// will match on zero spaces.
-
JPT about 4 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 almost 4 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 almost 4 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. almost 4 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 almost 4 yearsWhile using builtin functionality seems nice, extglob is very slow in my experience.
-
JL Peyret over 3 yearsFWIW,
var="${var//[[:space:]]/}"
works fine in re-assigning the trimmed contents back to the original variable. -
Daniel Alder over 3 years@DrBeco
#!/bin/sh
is not necessarily bash ;) -
DrBeco over 3 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 over 3 years
xargs <<< " test teste grdgdft"
-
David Scott Kirby about 3 yearsIt takes lots of examples because trimming a whitespace is about as easy as trimming your own hair.
-
David Scott Kirby about 3 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 about 3 yearsThe cleanest solution
-
mc2 about 3 yearsI'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 about 3 years@akhan, Yes, quotes are NOT needed in variable assignment in BASH: stackoverflow.com/questions/3958681/… unix.stackexchange.com/questions/97560/…
-
Ярослав Рахматуллин almost 3 years@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 almost 3 yearsThis helped me, but the question specifically asked about a trailing newlin which this does not remove.
-
AngryDane almost 3 yearsI tried two other solution from this question/answer page and only this one worked as expected, keep-it-simple-silly strikes again!!
-
Sridhar Sarnobat almost 3 yearsYou could even use process command substitution but I guess that won't work for Bourne Shell
-
Faither almost 3 yearsRelated to @mklement0 coment: mywiki.wooledge.org/IFS.
The default value of IFS is space, tab, newline. (A three-character string.)
... -
Zane almost 3 yearsGreat. Thanks for the function - added to my local library of valuabe functions.
-
black.swordsman over 2 yearsThis answer doesn't remove \r or CR from the end of a variable.
-
ardnew over 2 yearsYou 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 about 2 yearswill not work if the_string contains wildcards, e.g. "the_string=" foo * bar "
-
bobbogo about 2 yearsThat formulation for fewer lines is wrong. You can't do
${${f}}
in bash.