1

I created a script that will check for the existence of .gz files in the base directory and if it finds them it moved them into a new structure based on the current date. The script works perfectly when the shell is set to /bin/bash and I run it manually, but this script is run as a cron job (by logrotate) and I believe that it MUST be run under /bin/sh as I am not sure how to get logrotate to run it under /bin/bash. The code in question is

# Move rotated logs to the archive
if [ -f $BASEDIR/*.gz ]; then
        logger "$SNAME Moving rotated logs to $DIRECTORY"
        mv $BASEDIR/*.gz $DIRECTORY
else
        echo "$BASEDIR/*.gz"
        logger "$SNAME No rotated logs to move. Is this normal?"
fi

In bash the conditional check works great, under sh it complains there are too many arguments. If I put things in quotes it doesn't see the wildcard and aways returns false.

Any help would be fantastic!

hobbymaster001
  • 13
  • 1
  • 1
  • 4
  • As an aside -- all-caps names are used for variables with meaning to the OS or shell, whereas lowercase names are reserved for application use. See fourth paragraph of http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html – Charles Duffy Jun 21 '17 at 15:13
  • @CharlesDuffy, thank you for that information, I never knew that distinction and have always used all caps for globally available variables. – hobbymaster001 Jun 21 '17 at 15:16

2 Answers2

4

The problem here is that [ -f pathname ] takes exactly one name ([ -f one.gz two.gz ] isn't valid test syntax), but you don't know how many names *.gz expands to.

check() {
  set -- "$BASEDIR"/*.gz
  if [ -f "$1" ] || [ -L "$1" ]; then
    logger "$SNAME Moving rotated logs to $DIRECTORY"
    mv -- "$@" "$DIRECTORY"
  else
    echo "$BASEDIR/*.gz"
    logger "$SNAME No rotated logs to move. Is this normal?"
  fi
}
check

Breaking this down:

  • check() { ... } defines a function named check, which we then call later.
  • set -- "$BASEDIR"/*.gz replaces the function's argument list (this is why we're using a function, so we don't overwrite the whole script's argument list!) with a list of files with names ending in *.gz.
  • [ -f "$1" ] tests if the first name in this list exists -- if it does, then we know that the expansion was successful. [ -L "$1" ] can also be true if the glob successfully expanded but the first entry was a symlink to a file that doesn't exist; by including it, we cover that corner case.
  • mv -- "$@" "$DIRECTORY" reuses that argument list to pass to mv. The -- argument specifies to mv that all following arguments are names, even if they start with -s.
Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
  • Thank you a TON. This did the trick and everything works great! I find it interesting that the single file limit was not a problem in bash but in sh it was an issue. – hobbymaster001 Jun 21 '17 at 15:44
  • It *is* a problem in bash too -- I'm wondering if maybe you just didn't have more than one file ready to be transferred when testing earlier? – Charles Duffy Jun 21 '17 at 15:45
0

How about this:

if ls "$BASEDIR"/*.gz
then
    echo "moving them ..."
else
    echo "No such file!"
fi
Alfe
  • 56,346
  • 20
  • 107
  • 159
  • 1
    `if ls "$BASEDRI"/*.gz &> /dev/null`... – codeforester Jun 25 '17 at 04:16
  • 1
    My original answer also contained the suppressing of the output, but then I removed it because of clarity and because I had the feeling that OP might want to have this output, actually. In the else case there already was such a message, and I considered it also useful in the then case. But of course the suppression you proposed is standard in most such cases. – Alfe Jun 25 '17 at 12:29