Test if string has non whitespace characters in Bash
Solution 1
You can use bash's regex syntax.
It requires that you use double square brackets [[ ... ]]
, (more versatile, in general).
The variable does not need to be quoted. The regex itself must not be quoted
for str in " " "abc " "" ;do
if [[ $str =~ ^\ +$ ]] ;then
echo -e "Has length, and contain only whitespace \"$str\""
else
echo -e "Is either null or contain non-whitespace \"$str\" "
fi
done
Output
Has length, and contain only whitespace " "
Is either null or contain non-whitespace "abc "
Is either null or contain non-whitespace ""
Solution 2
Many of these answers are far more complex, or far less readable, than they should be.
[[ $string = *[[:space:]]* ]] && echo "String contains whitespace"
[[ $string = *[![:space:]]* ]] && echo "String contains non-whitespace"
Solution 3
A non-bash specific, shell only variant:
case "$string" in
*[!\ ]*) echo "known";;
*) echo "unknown";;
esac
Solution 4
[[ -z `echo $string` ]]
The backquotes execute the command within; bash line parsing convert tabs and newlines to blanks and joins double blanks. The echo command re-emits this string, which is shrunk to an empty string for the final test by [[ ]]. I think this is the shortest solution which passes the following:
> VAR="$(echo -e " \n\t")"
> [[ -z `echo $VAR` ]] ; echo $?
0
> VAR="$(echo -e " \na\t")"
> [[ -z `echo $VAR` ]] ; echo $?
1
> VAR="$(echo -e "aaa bbb")"
> [[ -z `echo $VAR` ]] ; echo $?
1
> VAR=
> [[ -z `echo $VAR` ]] ; echo $?
0
Solution 5
With extended globs enabled (shopt -s extglob
):
if [ -n "${string##+([[:space:]])}" ]; then
echo '$string has non-whitespace characters'
fi
Yamiko
Web applications developer and indie html5 game developer.
Updated on January 10, 2020Comments
-
Yamiko over 4 years
My script is reading and displaying id3 tags. I am trying to get it to echo unknown if the field is blank but every if statement I try will not work. The id3 tags are a fixed size so they are never null but if there is no value they are filled with white space. I.E the title tag is 30 characters in length. Thus far I have tried
echo :$string: #outputs spaces between the 2 ::
if [ -z "$string" ] #because of white space will always evaluate to true
x=echo $string | tr -d ' '; if [ -z "$string" ];
#still evaluates to true but echos :$x: it echos ::the script
#!bin/bash echo "$# files"; while [ "$i" != "" ]; do TAG=`tail -c 128 "$i" | head -c 3`; if [ $TAG="TAG" ] then ID3[0]=`tail -c 125 "$1" | head -c 30`; ID3[1]=`tail -c 95 "$1" | head -c 30`; ID3[2]=`tail -c 65 "$1" | head -c 30`; ID3[3]=`tail -c 35 "$1" | head 4`; ID3[4]=`tail -c 31 "$i" | head -c 28`; for i in "${ID3[@]}" do if [ "$(echo $i)" ] #the if statement mentioned then echo "N/A"; else echo ":$i:"; fi done else echo "$i does not have a proper id3 tag"; fi shift; done
-
Yamiko about 12 yearsIm looping through all tags and not all are 30 characters is there another way to test if a string is all spaces?
-
ams about 12 yearsDo the tags ever have spaces between words?
-
Yamiko about 12 yearsyep. and if a tag is 10 characters the rest of it is filled with spaces.
-
Yamiko about 12 yearsyour example is always evaluating to false for me
-
ams about 12 yearsOK, I thought I tested it. What's your input, exactly?
-
Yamiko about 12 yearsmp3 files the command im using is
ls *.mp3 | xargs ./myScript.sh
-
Yamiko about 12 yearswhile testing i encapsulated the string in :: to see what was being echoed
-
Yamiko about 12 yearsits out putting too many arguments and binary operator expected
-
Yamiko about 12 yearseverything is echoing with all white spaces
-
ams about 12 yearsWell, I tried my if statement with
string=" "
and it works. Same for @kev's solution. So I don't think your strings contain what you think they do. @kev's test fails if there's a hidden newline, but mine doesn't, so that's not it. Maybe there's a tab: neither test likes that? -
Yamiko about 12 yearsthey all echo including the ones I suspect to have spaces. is there a way I can verify they are spaces and not something else?
-
Peter.O about 12 yearsThanks yamikoWebs ... I started off using regex and then opted for globbing... I've reverted to regex... edited the answer to use bash's regex.
-
Charles Duffy almost 11 yearsBetter to use the POSIX character class
[[:space:]]
rather than listing\
specifically. -
Charles Duffy almost 11 yearsAs currently written this only checks for spaces, not for all whitespace characters -- it doesn't handle tabs, or newlines, or so forth.
-
Charles Duffy almost 10 years...also,
echo -e
is almost certainly the wrong thing here -- if you want to show nonprintable characters and render escape sequences literally, a more appropriate tool for the job might be:printf 'Has length, and contains only whitespace: "%q"\n' "$str"
-
Charles Duffy almost 10 years...but using
echo -e
means that you're rendering escape sequences into the literal characters they represent, which is getting further away from showing the user exactly what the data being handled is, not closer to it (if the data contains a literal backslash followed by an
, why would they want to see it in a manner indistinguishable from a literal newline character?) -
kkm over 8 yearsThis does not answer the question though. The OP's question was how to test whether a string contains at least one non-whitespace. This is a test for a string containing at least one whitespace.
-
Charles Duffy over 8 years@kkm, I'm embarrassed that the error survived so long. Resolved.
-
kkm over 8 years@CharlesDuffy: Thanks! Did not know about the
!
pattern negation. Cool bashism! -
Charles Duffy over 8 years@kkm, not a bashism -- that's POSIX fnmatch behavior, so it works in standard-compliant shell globbing expressions. See pubs.opengroup.org/onlinepubs/9699919799/utilities/…
-
Charles Duffy over 8 years...though, yes,
[[ ]]
is of course a bashism (well, a stolen/adopted ksh-ism) itself. :) -
Admin almost 5 yearsthis works, what exactly does
${var// }
represent? is it replacing something? -
MrPotatoHead almost 5 yearsYes. It substitutes null for a space character (aka "white space").
-
zenaan over 4 yearsThese do NOT work -except- in Bash:
test "abc" = *[[:space:]]*
andtest "a bc" = *[[:space:]]*
both return1
. Yes, the bang!
is POSIX, but except there is some other globbing mechanism that can somehow be enabled, the tests above only work in Bash. Also, without quotes, won't the*
glob have problems if filenames in $PWD contain spaces? -
Charles Duffy over 4 years@zenaan, see the title and tagging of this question -- in bash. The OP is asking about bash, so I'm only answering for bash here. And inside
[[ ]]
(in both bash and ksh), string-splitting and globbing are suppressed, so no more quotes are needed than provided. -
Charles Duffy over 4 years@zenaan, ...if you wanted a POSIX-compliant answer, use
case
instead. -
Charles Duffy over 4 years@zenaan, ...so, when I said "not a bashism" above, I was referring to
!
inside a pattern, not to the answer as a whole.