Using exec in find over ssh from shell script

6,222

Solution 1

You forgot to add an ';':

ssh -q $CUR_HOST "cd $LOGS_DIR; echo cd $LOGS_DIR; find . -name *.log -mmin +1440 -exec gzip {} \;; exit"

Because of the missing ;, find interprets exit as a path.

Solution 2

There are several syntax problems, one of which is fatal and another which is likely to bite you at some point.

By the way, you can use + instead of ; to end the -exec directive; this way gzip will be executed in batches, which is slightly faster.

If the value of LOGS_DIR is /somewhere/with/logs, then the following command is executed on the remote host:

cd /somewhere/with/logs; echo cd /somewhere/with/logs; find . -name *.log -mmin +1440 -exec gzip {} \; exit

or, substituting newlines for the equivalent semicolon operator:

cd /somewhere/with/logs
echo cd /somewhere/with/logs
find . -name *.log -mmin +1440 -exec gzip {} \; exit

When find sees that spurious exit after the -exec … ; directive, it doesn't know what to do with it; it hazards a (wrong) guess that you meant it to be a path to traverse. You need a command separator: put another ; after \; (with or without a space before).

A second problem is that the wildcard pattern *.log will be expanded in the directory /somewhere/with/logs. If there is a matching file (i.e. if there is a file of the form /somewhere/with/logs/something.log), the pattern will be replaced by that matching file. It's only if there is no match that *.log remains unchanged by the remote shell and is seen by find. Add quotes around the pattern to prevent this.

A third problem is with the value of LOGS_DIR. It is expanded locally into a string which is executed as a shell script on the remote side. So if there are any shell special characters (whitespace, $, etc.) in it, this can execute an arbitrary remote command. A quick-and-dirty way to quote most characters is to put single quotes around the variable expansion; this will break only if the value contains single quotes. If your local script is running bash, you can replace single quotes by the 4-character sequence '\'' to protect the value of LOGS_DIR:

ssh -q "$CUR_HOST" "cd '${LOGS_DIR//\'/\'\\\'\'}'; find . -name '*.log' -mmin +1440 -exec gzip {} +; exit"
Share:
6,222

Related videos on Youtube

Skittles
Author by

Skittles

if [ problem -gt solution ]; then rm -rf / fi

Updated on September 18, 2022

Comments

  • Skittles
    Skittles over 1 year

    So, I am attempting to execute the following from within a shell script;

    ssh -q $CUR_HOST "cd $LOGS_DIR; echo cd $LOGS_DIR; find . -name *.log -mmin +1440 -exec gzip {} \; exit"
    

    When this runs, it generates the following error;

    find: paths must precede expression
    Usage: find [-H] [-L] [-P] [path...] [expression]
    

    I've tried numerous variations based on things found on Google, but none seem to resolve this problem. Could anyone tell me what is wrong with this?

    As a side note, when I manually login to the target host and run the same find command there, it works just fine. So, I'm led to think that it's something to do with the command being embedded in the double quotes of the ssh command.

    • Stéphane Chazelas
      Stéphane Chazelas almost 10 years
      Quote *.log ('*.log') to prevent globbing in the remote shell.
    • Skittles
      Skittles almost 10 years
      Thanks...Do I need to also include the parens or just the single quotes?
    • Skittles
      Skittles almost 10 years
      I just tried '*.log', but still the same error.
  • Skittles
    Skittles almost 10 years
    That's precisely what the doctor ordered! Makes sense now as the first semi-colon was escaped for the find exec. Thank you.
  • Stéphane Chazelas
    Stéphane Chazelas almost 10 years
    Note that if the login shell of the remote user is (t)csh, that escaping will still not work if $LOGS_DIR contains newline characters.
  • Skittles
    Skittles almost 10 years
    Although I already accepted the previously submitted answer, this one's verbosity is extremely admirable and highly appreciated! I would just like to personally extend a thanks to you for the detail to which you displayed in this answer.