12

Objective: Check for presence of backup .tgz file containing today's date; output 1 for OK, 0 for no file.

I'm a sucker for one liners :) For example in PHP (and pretty much similar in Javascript), in various scenarios I like to do something like

<?php
echo (date("d")==1)?"Monday":"Not Monday";
?>

Is there similar syntax in Bash? I know how to check for presence of a regular file using -f FILENAME, I only want the command to print 1 or 0 :)

  • 2
    Why isn't -f enough then? That already returns 0 or 1. Do you want the 0 or 1 to be printed or returned? – terdon Oct 9 '18 at 13:26
  • @terdon that would be printed – DavDav Oct 9 '18 at 13:50
  • @DavDav "I'm a sucker for one liners" You do not need a line break after <?php, and it is advised not to use ?> at the end of a PHP program. – rexkogitans Oct 9 '18 at 15:35
26

You can simply do this :

#to check if it's a regular file
[ -f "/you/file.file" ] && echo 1 || echo 0
#to check if a file exist
[ -e "/you/file.file" ] && echo 1 || echo 0

In shell this charater [ means test, -e if file exists ] end of test && if command return true execute the command after, || if command return false execute command after.
This should work in shell and bash

| improve this answer | |
  • 8
    It's important to know that if the 'true' command fails, the 'false' command will be executed too – IanM_Matrix1 Oct 9 '18 at 15:21
16
if [ ! -f /tmp/foo.txt ]; then echo "File not found!"; else echo "file found"; fi
| improve this answer | |
  • 2
    It should be noted (since the type of person asking a question like this might not think about it) that -f will only alert you of the existence of files you are allowed to see. If you don't have sufficient permissions on a directory, you can't see files within it, even if you specify the full path of the file. – jeremysprofile Oct 9 '18 at 16:35
  • Thanks for input - I am aware of this. In the specific case at hand, the user running the script has sufficient permissions in the particular folder. – DavDav Oct 11 '18 at 8:35
9

With zsh:

(){echo $#} *"$(date +%Y-%m-%d)"*.tgz(DN)

Would output the number of files in the current directory whose name contains the current date in YYYY-mm-dd format and end in .tgz as a decimal number. Replace (DN) with (DN[1]) if you want only 0 or 1.

To use as the condition in an if statement, you can do:

if ()(($#)) *"$(date +%Y-%m-%d)"*.tgz(DN); then
   echo found
else
   echo none found
fi

In bash

the equivalent could be:

(shopt -s nullglob dotglob; set -- *"$(date +%Y-%m-%d)"*.tgz; echo "$#")

(replace "$#" with "$(($#>0))" to get 0 or 1).

and

if (shopt -s nullglob dotglob; set -- *"$(date +%Y-%m-%d)"*.tgz; (($#))); then
   echo found
else
   echo none found
fi

With ksh93:

(FIGNORE='@(.|..)'; set -- ~(N)*"$(date +%Y-%m-%d)"*.tgz; echo "$#")

and

if (FIGNORE='@(.|..)'; set -- ~(N)*"$(date +%Y-%m-%d)"*.tgz; (("$#"))); then...

POSIXly

ls -qA | grep -c "$(date +%Y-%m-%d).*\.tgz$"

for the count.

ls -qA | grep -q "$(date +%Y-%m-%d).*\.tgz$"; echo "$(($? == 0))"

for 0 or 1 and:

And:

if ls -qA | grep -q "$(date +%Y-%m-%d).*\.tgz$"; then...

Though the common wisdom is not to parse the output of ls, here with -q, we're making sure there's one file per line and the replacing of non-printable characters with ? shouldn't affect the greping for our pattern so it should be relatively safe.

You may see differences if the file names contain sequences of bytes that don't form valid characters. One advantage is that you'll get an error message if the current directory is no readable.

| improve this answer | |
  • The question explicitly mentions bash, it is tagged bash, and it was like that from the beginning. Why is your main answer about a different shell no one asked for? – pipe Oct 9 '18 at 14:06
  • 5
    @pipe, the answer covers bash as well. The answer is not only for the OP, not everybody's restricted to using bash. Even the OP could consider switching to a different shell. – Stéphane Chazelas Oct 9 '18 at 14:46
  • @pipe I'm a fan of zsh. Every bash user should consider switching IMHO. – Henno Brandsma Oct 9 '18 at 16:18
  • @HennoBrandsma Write a blog about it. This is absolutely the wrong place for fanboyism. – pipe Oct 10 '18 at 7:57
6

You can use this command:

test -e *$(date).tgz && echo 1 || echo 0
| improve this answer | |
  • 7
    Note that this doesn't actually return 1 or 0. It prints 1 or 0 which is a different thing. If you want to return 1 or 0, just use the test -e part and forget the rest. The test command already returns 0 or 1 depending on its status. – terdon Oct 9 '18 at 13:24
  • Except that test returns the opposite of what the OP wants. – alwayslearning Oct 9 '18 at 15:22
  • how would this behave if there were more than one file matching the wildcard? – Grump Oct 9 '18 at 15:48
4

As yet another variant, if you knew the exact format of the filename you were looking for you could use

[ ! -f FILENAME ]; echo $?

or

echo `[ ! -f FILENAME ]` $?

however this couldn't cope with wildcards, so files ending in .tgz containing today's date would need something more complex, such as

echo $( for entry in *$(date --rfc-3339=date)*.tgz; do [ -f "$entry" ] && exit 1; done; exit 0 ) $?
| improve this answer | |
0

I know you asked for Bash, but if you're looking for any command line program that will work, I recommend Python:

python -c "import os; exists = os.path.isfile('myFile.txt'); print(int(exists))"
| improve this answer | |
0
ls filename 2> /dev/null && echo 1 || echo 0

Or, if you want it in a variable

EXISTS=$(ls filename 2> /dev/null && echo 1 || echo 0)
| improve this answer | |
  • 1
    What is the advantage of ls compared to test? – RalfFriedl Oct 9 '18 at 19:43

Not the answer you're looking for? Browse other questions tagged or ask your own question.