Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Test if a command outputs an empty string

Tags:

bash

shell

How can I test if a command outputs an empty string?

like image 213
barp Avatar asked Aug 27 '12 06:08

barp


People also ask

How do I check if a string is empty in shell script?

To check if string is empty in Bash, we can make an equality check with the given string and empty string using string equal-to = operator, or use -z string operator to check if the size of given string operand is zero.

How do you check if a parameter is empty?

PHP empty() Function The empty() function checks whether a variable is empty or not. This function returns false if the variable exists and is not empty, otherwise it returns true. The following values evaluates to empty: 0.

Which of the following options will result with outputting a non empty string to the console?

The -n test will check if $output is a non-empty string. If it is, the content of $output will be printed.


2 Answers

Previously, the question asked how to check whether there are files in a directory. The following code achieves that, but see rsp's answer for a better solution.


Empty output

Commands don’t return values – they output them. You can capture this output by using command substitution; e.g. $(ls -A). You can test for a non-empty string in Bash like this:

if [[ $(ls -A) ]]; then     echo "there are files" else     echo "no files found" fi 

Note that I've used -A rather than -a, since it omits the symbolic current (.) and parent (..) directory entries.

Note: As pointed out in the comments, command substitution doesn't capture trailing newlines. Therefore, if the command outputs only newlines, the substitution will capture nothing and the test will return false. While very unlikely, this is possible in the above example, since a single newline is a valid filename! More information in this answer.


Exit code

If you want to check that the command completed successfully, you can inspect $?, which contains the exit code of the last command (zero for success, non-zero for failure). For example:

files=$(ls -A) if [[ $? != 0 ]]; then     echo "Command failed." elif [[ $files ]]; then     echo "Files found." else     echo "No files found." fi 

More info here.

like image 115
Will Vousden Avatar answered Oct 05 '22 17:10

Will Vousden


TL;DR

if [[ $(ls -A | head -c1 | wc -c) -ne 0 ]]; then ...; fi

Thanks to netj for a suggestion to improve my original:
if [[ $(ls -A | wc -c) -ne 0 ]]; then ...; fi


This is an old question but I see at least two things that need some improvement or at least some clarification.

First problem

First problem I see is that most of the examples provided here simply don't work. They use the ls -al and ls -Al commands - both of which output non-empty strings in empty directories. Those examples always report that there are files even when there are none.

For that reason you should use just ls -A - Why would anyone want to use the -l switch which means "use a long listing format" when all you want is test if there is any output or not, anyway?

So most of the answers here are simply incorrect.

Second problem

The second problem is that while some answers work fine (those that don't use ls -al or ls -Al but ls -A instead) they all do something like this:

  1. run a command
  2. buffer its entire output in RAM
  3. convert the output into a huge single-line string
  4. compare that string to an empty string

What I would suggest doing instead would be:

  1. run a command
  2. count the characters in its output without storing them
    • or even better - count the number of maximally 1 character using head -c1
      (thanks to netj for posting this idea in the comments below)
  3. compare that number with zero

So for example, instead of:

if [[ $(ls -A) ]] 

I would use:

if [[ $(ls -A | wc -c) -ne 0 ]] # or: if [[ $(ls -A | head -c1 | wc -c) -ne 0 ]] 

Instead of:

if [ -z "$(ls -lA)" ] 

I would use:

if [ $(ls -lA | wc -c) -eq 0 ] # or: if [ $(ls -lA | head -c1 | wc -c) -eq 0 ] 

and so on.

For small outputs it may not be a problem but for larger outputs the difference may be significant:

$ time [ -z "$(seq 1 10000000)" ]  real    0m2.703s user    0m2.485s sys 0m0.347s 

Compare it with:

$ time [ $(seq 1 10000000 | wc -c) -eq 0 ]  real    0m0.128s user    0m0.081s sys 0m0.105s 

And even better:

$ time [ $(seq 1 10000000 | head -c1 | wc -c) -eq 0 ]  real    0m0.004s user    0m0.000s sys 0m0.007s 

Full example

Updated example from the answer by Will Vousden:

if [[ $(ls -A | wc -c) -ne 0 ]]; then     echo "there are files" else     echo "no files found" fi 

Updated again after suggestions by netj:

if [[ $(ls -A | head -c1 | wc -c) -ne 0 ]]; then     echo "there are files" else     echo "no files found" fi 

Additional update by jakeonfire:

grep will exit with a failure if there is no match. We can take advantage of this to simplify the syntax slightly:

if ls -A | head -c1 | grep -E '.'; then     echo "there are files" fi  if ! ls -A | head -c1 | grep -E '.'; then     echo "no files found" fi 

Discarding whitespace

If the command that you're testing could output some whitespace that you want to treat as an empty string, then instead of:

| wc -c 

you could use:

| tr -d ' \n\r\t ' | wc -c 

or with head -c1:

| tr -d ' \n\r\t ' | head -c1 | wc -c 

or something like that.

Summary

  1. First, use a command that works.

  2. Second, avoid unnecessary storing in RAM and processing of potentially huge data.

The answer didn't specify that the output is always small so a possibility of large output needs to be considered as well.

like image 44
rsp Avatar answered Oct 05 '22 17:10

rsp