I have a directory with crash logs, and I'd like to use a conditional statement in a bash script based on a find command.

The log files are stored in this format:


I want the if statement to only return true if there is a crash log for a specific app which has been modified in the last 5 minutes. The find command that I would use is:

find /var/log/crashes -name app-\*\.log -mmin -5

I'm not sure how to incorporate that into an if statement properly. I think this might work:

if [ test `find /var/log/crashes -name app-\*\.log -mmin -5` ] then
 service myapp restart

There are a few areas where I'm unclear:

  • I've looked at the if flags but I'm not sure which one, if any, that I should use.
  • Do I need the test directive or should I just process against the results of the find command directly, or maybe use find... | wc -l to get a line count instead?
  • Not 100% necessary to answer this question, but test is for testing against return codes that commands return? And they are sort of invisible - outside of stdout / stderr? I read the man page but I'm still pretty unclear about when to use test and how to debug it.
  • 1
    The real answer to the general case is to use find ... -exec. Also see the example commands under Why is looping over find's output bad practice?
    – Wildcard
    Commented Oct 18, 2017 at 23:59
  • @Wildcard - unfortunately that doesn't solve the general case: it doesn't work if there is more than one match and the action needs to only run once, and it doesn't work if you need an action to run when there are no matches. The former can be solved by using ... -exec command ';' -quit, but I don't believe there is any solution for the latter other than parsing the result. Also, in either case, the primary problem with parsing the result of find (i.e. inability to distinguish delimiters from characters in filenames) doesn't apply, as you don't need to find delimiters in these cases.
    – Jules
    Commented Feb 1, 2018 at 18:12
  • -exec is good for quick response, but for wider conditions if find ... | grep . is better: unix.stackexchange.com/a/684153/43233
    – Noam Manos
    Commented Dec 28, 2021 at 10:29
  • Easier to check systemd status, or if the process is running
    – Freedo
    Commented Dec 28, 2021 at 10:40

7 Answers 7


[ and test are synonyms (except [ requires ]), so you don't want to use [ test:

[ -x /bin/cat ] && echo 'cat is executable'
test -x /bin/cat && echo 'cat is executable'

test returns a zero exit status if the condition is true, otherwise nonzero. This can actually be replaced by any program to check its exit status, where 0 indicates success and non-zero indicates failure:

# echoes "command succeeded" because echo rarely fails
if /bin/echo hi; then echo 'command succeeded'; else echo 'command failed'; fi

# echoes "command failed" because rmdir requires an argument
if /bin/rmdir; then echo 'command succeeded'; else echo 'command failed'; fi

However, all of the above examples only test against the program's exit status, and ignore the program's output.

For find, you will need to test if any output was generated. -n tests for a non-empty string:

if [[ -n $(find /var/log/crashes -name "app-*.log" -mmin -5) ]]
    service myapp restart

A full list of test arguments is available by invoking help test at the bash commandline.

If you are using bash (and not sh), you can use [[ condition ]], which behaves more predictably when there are spaces or other special cases in your condition. Otherwise it is generally the same as using [ condition ]. I've used [[ condition ]] in this example, as I do whenever possible.

I also changed `command` to $(command), which also generally behaves similarly, but is nicer with nested commands.

  • echo can fail: try echo 'oops' > /dev/full.
    – derobert
    Commented Aug 28, 2012 at 22:52
  • This answer beats all around the root of the problem but gracefully avoids mentioning exactly what that is.
    – bahamat
    Commented Aug 29, 2012 at 22:05
  • @bahamat: And how does your cmt improve things? If you have something to say, please - say it.
    – Seamus
    Commented Nov 23, 2023 at 6:53

find will exit successfully if there weren't any errors, so you can't count on its exit status to know whether it found any file. But, as you said, you can count how many files it found and test that number.

It would be something like this:

if [ $(find /var/log/crashes -name 'app-*.log' -mmin -5 | wc -l) -gt 0 ]; then

test (aka [) doesn't check the error codes of the commands, it has a special syntax to do tests, and then exits with an error code of 0 if the test was successful, or 1 otherwise. It is if the one that checks the error code of the command you pass to it, and executes its body based on it.

See man test (or help test, if you use bash), and help if (ditto).

In this case, wc -l will output a number. We use test's option -gt to test if that number is greater than 0. If it is, test (or [) will return with exit code 0. if will interpret that exit code as success, and it will run the code inside its body.


This would be

if [ -n "$(find /var/log/crashes -name app-\*\.log -mmin -5)" ]; then


if test -n "$(find /var/log/crashes -name app-\*\.log -mmin -5)"; then

The commands test and [ … ] are exactly synonymous. The only difference is their name, and the fact that [ requires a closing ] as its last argument. As always, use double quotes around the command substitution, otherwise the output of the find command will be broken into words, and here you'll get a syntax error if there is more than one matching file (and when there are no arguments, [ -n ] is true, whereas you want [ -n "" ] which is false).

In ksh, bash and zsh but not in ash, you can also use [[ … ]] which has different parsing rules: [ is an ordinary command, whereas [[ … ]] is a different parsing construct. You don't need double quotes inside [[ … ]] (though they don't hurt). You still need the ; after the command.

if [[ -n $(find /var/log/crashes -name app-\*\.log -mmin -5) ]]; then

This can potentially be inefficient: if there are many files in /var/log/crashes, find will explore them all. You should make find stop as soon as it finds a match, or soon after. With GNU find (non-embedded Linux, Cygwin), use the -quit primary.

if [ -n "$(find /var/log/crashes -name app-\*\.log -mmin -5 -print -quit)" ]; then

With other systems, pipe find into head to at least quit soon after the first match (find will die of a broken pipe).

if [ -n "$(find /var/log/crashes -name app-\*\.log -mmin -5 -print | head -n 1)" ]; then

(You can use head -c 1 if your head command supports it.)

Alternatively, use zsh.

if (($#crash_files)); then

This should work

if find /var/log/crashes -name 'app-\*\.log' -mmin -5 | read
  service myapp restart
find /var/log/crashes -name app-\*\.log -mmin -5 -exec service myapp restart ';' -quit

is an appropriate solution here.

-exec service myapp restart ';' causes find to invoke the command that you want to run directly, rather than needing the shell to interpret anything.

-quit causes find to exit after processing the command, thus preventing the command being executed again if there happen to be multiple files that match the criteria.


You can do this by putting the output of find into a variable, and then using bash's test, to handle the different cases you're interested in. The simple case is whether there are any results or not:

mycrashedapp=$(find /var/log/crashes/ -name myapp-\*\.log -mmin -5)
# if no crash then the variable is empty
if [[ -z "${mycrashedapp}" ]];then
  echo "myapp is behaving."
  service myapp restart

At this point, you can do further handling, if needed, using bash's variable manipulation:

myappcrashedcount="$(((${#mycrashedapp} - ${#parse}) / ${#substr}))"

echo "myapp has crashed ${myappcrashedcount} times in total."

You can do further processing with bash's builtin regex pattern matching:

if [[ "${mycrashedapp}" =~ myapp-([0-9\-]*).log ]]; then
  echo "The dates and times that myapp has crashed:"
  echo ${BASH_REMATCH[1]}

Piping the find command to grep . would print the find results, in addition to the if condition response:

if find -name "*.log" | grep . ; then echo Found; else echo Nothing; fi


And when nothing is found:

if find -name "*.gol" | grep . ; then echo Found; else echo Nothing; fi


  • Use grep -q . to avoid printing and to terminate at the first match.
    – Kusalananda
    Commented Dec 28, 2021 at 11:03

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .