In bash I can use -z string
and -n string
to see if the string length is zero or not.
Would like to write a bash function that returns true or false, not only if length is zero but also if it is all whitespace. Or is there a way without needing a function?

- 12,024
- 2
- 30
- 47

- 57
- 1
- 5
3 Answers
You can use a regular expression:
if [[ $string =~ ^" "*$ ]]
or you can remove all the spaces before testing with -z
:
if [[ -z "${string// /}" ]]

- 741,623
- 53
- 500
- 612
-
Both are different as `[:space:]` encompasses a larger set of possible characters. – kvantour Sep 08 '21 at 20:40
-
@kvantour If you want to include all spacey characters in the second form, use `[[ -z "${string//[[:space:]]/}" ]]` – Gordon Davisson Sep 08 '21 at 20:43
-
I know, I just wasn't sure how to just match space in a bash regexp, because quoting a regexp makes it literal. @kvantour – Barmar Sep 08 '21 at 20:44
-
@Barmar `[[ $string =~ ^" "*$ ]]` – kvantour Sep 08 '21 at 20:47
-
If I make a function `zblank` that returns either `1` or `0`, could I do the following: `[[ zblank "$s" ]] && printf '%s\n' "Option not used"`. – Angio Sep 08 '21 at 20:49
-
Only the parts you actually quote are treated literally. `[[ $string =~ ^\ *$ ]]` or `[[ $string %" "*$ ]]` would work. That said, a common workaround is to store the regex in a variable, then use an unquoted parameter expansion, like `regex="^ *$"; [[ $string =~ $regex ]]`. – chepner Sep 08 '21 at 20:53
-
@Angio With a function, you wouldn't use `[[ ]]` -- those allow you to use a conditional expression in place of a command, but a function is already a command. So just use `zblank "$s" && printf '%s\n' "Option not used"`. My answer [here](https://stackoverflow.com/questions/49849957/bash-conditional-based-on-exit-code-of-command/49850110#49850110) has more explanation of a similar situation. – Gordon Davisson Sep 08 '21 at 22:11
-
@GordonDavisson Actually `[[ zblank "$s" ]]` did not work but `[[ $(lg "$s") ]]` did work. Will check out your way. – Angio Sep 08 '21 at 22:28
-
@GordonDavisson To do the negation of the function command, how would I go with your strategy? – Angio Sep 08 '21 at 22:29
-
@Angio `[[ $(lg "$s") ]]` is testing whether `lg` prints anything, not checking its exit status. Is your function printing something, or `return`ing a status? Oh, and to negate it you'd use either `! zblank "$s" && printf ...` or `zblank "$s" || printf ...` – Gordon Davisson Sep 08 '21 at 22:48
-
Its purpose is more intended to be a status value. – Angio Sep 08 '21 at 23:05
-
@Angio In that case, there's something wrong with how the function's written. Try `zblank() { if [[ $string =~ ^" "*$ ]]; then return 0; else return 1; fi; }` or even simpler just `zblank() { [[ $1 =~ ^" "*$ ]]; }` (since functions implicitly return the status of the last command in them). – Gordon Davisson Sep 09 '21 at 00:10
-
That's what I've done. Using `zblank "$src" && printf '%s\n' "src used"` is still valid, am I correct? – Angio Sep 09 '21 at 00:26
-
You don't quote `$string` when using regular expressions? – Angio Sep 09 '21 at 01:36
-
@Angio It's not necesssary to quote variables inside `[[ ]]`, because there's no word splitting in that context. – Barmar Sep 09 '21 at 14:12
If you want it to be portable to non-bash shells (e.g. dash, which is the default /bin/sh on some Linux distros), you can use this:
if [ "$variable" = "${variable#*[![:space:]]}" ]; then
Explanation: ${variable%pattern}
will remove a match of the pattern from the beginning of the variable's value if there is such a match. The pattern *[![:space:]]
will match from the beginning of the string through the first non-space character (if there are any non-space characters in the string). Therefore, if there's at least one non-space character, the pattern will match and the variable's value will change, so the =
test will fail. On the other hand if the string doesn't contain any non-space characters, the pattern won't match, the variable won't be modified, and the =
test will succeed.
For completeness, you can also use case
for this:
case "$variable" in
*[![:space:]]* ) echo "variable is NOT empty" ;;
* ) echo "variable IS empty" ;;
esac
Either of these should work in any POSIX-compliant shell.

- 118,432
- 16
- 123
- 151
-
-
@kvantour Yep, according to [the POSIX specification](https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_13_01) bracket expressions in a glob are almost identical to in a regex. The only difference is you use `!` instead of `^` to negate the expression. – Gordon Davisson Sep 08 '21 at 20:56
Use the exit status of grep -Pq '\S'
, which is true
if there is at least 1 non-whitespace character, and false
otherwise:
grep -Pq '\S' <<< " " && echo "not all whitespace" || echo "all whitespace"
# all whitespace
grep -Pq '\S' <<< "" && echo "not all whitespace" || echo "all whitespace"
# all whitespace
grep -Pq '\S' <<< "a" && echo "not all whitespace" || echo "all whitespace"
# not all whitespace
Here, GNU grep
uses the following options:
-P
: Use Perl regexes.
-q
: Quiet; do not write anything to standard output. Exit immediately with zero status if any match is found.
\S
: non-whitespace character.
SEE ALSO:
grep
manual
perlre - Perl regular expressions

- 12,024
- 2
- 30
- 47