25

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
6
  • Michal Politowski: -z means operand has zero length Commented Mar 19, 2012 at 10:03
  • @Peter.O: yes, and $x is the string that should be tested, not $string. Commented Mar 19, 2012 at 10:10
  • yes i was using $string as an example before i uploaded the script; $i is the string which is a value from the array. Is there possibly something wrong with my loop? Commented Mar 19, 2012 at 10:14
  • You also have to change if [ $TAG="TAG" ] to if [ "$TAG" = "TAG" ] -- the first version sends only a single non-empty argument to the [ command so it always returns true. Commented Mar 19, 2012 at 13:01
  • @yamikoWebs As well as glenn jackman's comment, you have mixed up your $1 and $i, and head 4 (?) head -c 4 ... With those issues fixed, and your choice of if statement, the script works :) Commented Mar 19, 2012 at 16:35

8 Answers 8

39

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"
Sign up to request clarification or add additional context in comments.

9 Comments

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.
@kkm, I'm embarrassed that the error survived so long. Resolved.
@CharlesDuffy: Thanks! Did not know about the ! pattern negation. Cool bashism!
@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/…
...though, yes, [[ ]] is of course a bashism (well, a stolen/adopted ksh-ism) itself. :)
|
8

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 "" 

5 Comments

everything is echoing with all white spaces
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.
As currently written this only checks for spaces, not for all whitespace characters -- it doesn't handle tabs, or newlines, or so forth.
...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"
...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?)
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

Comments

3

A non-bash specific, shell only variant:

case "$string" in
 *[!\ ]*) echo "known";;
 *) echo "unknown";;
esac

1 Comment

Better to use the POSIX character class [[:space:]] rather than listing \ specifically.
1

With extended globs enabled (shopt -s extglob):

if [ -n "${string##+([[:space:]])}" ]; then
    echo '$string has non-whitespace characters'
fi

2 Comments

its out putting too many arguments and binary operator expected
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?
0
if [ "$(echo "$string" | tr -s ' ')" == " " ]; then
  echo "all white space"
fi

That compresses all repeated spaces down to one space, and compares for that.

8 Comments

Im looping through all tags and not all are 30 characters is there another way to test if a string is all spaces?
Do the tags ever have spaces between words?
yep. and if a tag is 10 characters the rest of it is filled with spaces.
your example is always evaluating to false for me
OK, I thought I tested it. What's your input, exactly?
|
0

This one checks for Zero length or SPACE or TAB

S="Something"
if [[ "x$S" == "x" || "x$S" == x*\ * || "x$S" == x*\    * ]] ;then
  echo "Is not OK"
else
  echo "Is OK"
fi

Comments

0

Sharing a more portable method not requiring double-brackets [[ ]] while keeping it simple, as much as possible.

Detect a string containing ONLY white space or = null:

if [ -z "${string// }" ]; then <do something>; fi

Which in this case would be:

${var// }

Such as:

if [ -z "${string// }" ]; then echo "It's empty!"; fi

What this does is simply replace all white space with null through substitution. If $string contains only white space, the -z test will evaluate TRUE. If there are non-white space characters in the string, the equation evaluates to FALSE.

Elaborating further on BASH (since OP asked about this in BASH), the example above will not catch tabs, though it is possible to do so. Here are more examples in BASH that do and don't work as expected.

Let's say there's a tab in the search string.

This works:

string=$(echo -e "\t"); if [ -z ${string// } ]; then echo "It's empty!"; fi

But these don't:

string=$(echo -e "\t"); if [ -z "${string// }" ]; then echo "It's empty!"; fi
string=$(echo -e "\t"); if [ -z '${string// }' ]; then echo "It's empty!"; fi

The two last examples above both report the string is not empty. If you consider a tab to be white space, that would be a problem and you'd want to use the first example.

What about newline? Let's take a look at an \n scenario. First off, "correct" behavior depends on your expectations.

These treat newlines (\n) as white space (equation evaluates TRUE):

string=$(echo -e "\n\n"); if [ -z ${string// } ]; then echo "It's empty!"; fi
string=$(echo -e "\n\n"); if [ -z "${string// }" ]; then echo "It's empty!"; fi

This doesn't (equation evaluates to FALSE), meaning this equation thinks a newline is not white space.

string=$(echo -e "\n\n"); if [ -z '${string// }' ]; then echo "It's empty!"; fi

If you require checking for newlines and tabs and spaces, you may need to use two IF/THEN statements or the CASE method described above.

2 Comments

this works, what exactly does ${var// } represent? is it replacing something?
Yes. It substitutes null for a space character (aka "white space").

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.