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