Test if string has non whitespace characters in Bash

22,822

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
Share:
22,822
Yamiko
Author by

Yamiko

Web applications developer and indie html5 game developer.

Updated on January 10, 2020

Comments

  • Yamiko
    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
    Yamiko about 12 years
    Im looping through all tags and not all are 30 characters is there another way to test if a string is all spaces?
  • ams
    ams about 12 years
    Do the tags ever have spaces between words?
  • Yamiko
    Yamiko about 12 years
    yep. and if a tag is 10 characters the rest of it is filled with spaces.
  • Yamiko
    Yamiko about 12 years
    your example is always evaluating to false for me
  • ams
    ams about 12 years
    OK, I thought I tested it. What's your input, exactly?
  • Yamiko
    Yamiko about 12 years
    mp3 files the command im using is ls *.mp3 | xargs ./myScript.sh
  • Yamiko
    Yamiko about 12 years
    while testing i encapsulated the string in :: to see what was being echoed
  • Yamiko
    Yamiko about 12 years
    its out putting too many arguments and binary operator expected
  • Yamiko
    Yamiko about 12 years
    everything is echoing with all white spaces
  • ams
    ams about 12 years
    Well, 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
    Yamiko about 12 years
    they 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
    Peter.O about 12 years
    Thanks 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
    Charles Duffy almost 11 years
    Better to use the POSIX character class [[:space:]] rather than listing \ specifically.
  • Charles Duffy
    Charles Duffy almost 11 years
    As currently written this only checks for spaces, not for all whitespace characters -- it doesn't handle tabs, or newlines, or so forth.
  • Charles Duffy
    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
    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 a n, why would they want to see it in a manner indistinguishable from a literal newline character?)
  • kkm
    kkm over 8 years
    This 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
    Charles Duffy over 8 years
    @kkm, I'm embarrassed that the error survived so long. Resolved.
  • kkm
    kkm over 8 years
    @CharlesDuffy: Thanks! Did not know about the ! pattern negation. Cool bashism!
  • Charles Duffy
    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
    Charles Duffy over 8 years
    ...though, yes, [[ ]] is of course a bashism (well, a stolen/adopted ksh-ism) itself. :)
  • Admin
    Admin almost 5 years
    this works, what exactly does ${var// } represent? is it replacing something?
  • MrPotatoHead
    MrPotatoHead almost 5 years
    Yes. It substitutes null for a space character (aka "white space").
  • zenaan
    zenaan over 4 years
    These do NOT work -except- in Bash: test "abc" = *[[:space:]]* and test "a bc" = *[[:space:]]* both return 1. 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
    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
    Charles Duffy over 4 years
    @zenaan, ...if you wanted a POSIX-compliant answer, use case instead.
  • Charles Duffy
    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.