eckza
eckza

Reputation: 2270

bash script + rsync: bash won't sync to host?

I've only been writing actual .sh scripts since sometime this morning, and I'm a bit stuck. I'm trying to write a script to check to see if a process is running, and to start it if it isn't. (I plan to run this script once every 10 to 15 minutes with cron.)

Here's what I have so far:

#!/bin/bash

APPCHK=$(ps aux | grep -c "/usr/bin/rsync -rvz -e ssh /home/e-smith/files/ibays/drive-i/files/Warehouse\ Pics/organized_pics  [email protected]:~/webapps/pavlick_container/public/images
")

RUNSYNC=$(rsync -rvz -e ssh /home/e-smith/files/ibays/drive-i/files/Warehouse\ Pics/organized_pics  [email protected]:~/webapps/pavlick_container/public/images)

if [ $APPCHK < '2' ];
  then
    $RUNSYNC
fi

exit

Here's the error that I'm getting:

$ ./image_sync.sh 
rsync: mkdir "/home/i/webapps/pavlick_container/public/images" failed: No such file or directory (2)
rsync error: error in file IO (code 11) at main.c(595) [Receiver=3.0.7]
rsync: connection unexpectedly closed (9 bytes received so far) [sender]
rsync error: error in rsync protocol data stream (code 12) at io.c(601) [sender=3.0.7]
./image_sync.sh: line 8: 2: No such file or directory

TRTWF is that

rsync -rvz -e ssh /home/e-smith/files/ibays/drive-i/files/Warehouse\ Pics/organized_pics [email protected]:~/webapps/pavlick_container/public/images

runs just fine from a terminal window.

What am I doing wrong?

Upvotes: 3

Views: 1988

Answers (5)

  • Your grep call is wrong on two counts. The pattern shouldn't include a newline. To look for an exact string, use grep -F 'substring' or grep -xF 'exact whole line'.
  • Finding if a process is running with ps | grep is highly brittle. On most unices (at least Solaris, Linux and *BSD), use pgrep: pgrep -f 'PATTERN' returns true if there's a running process whose command line matches PATTERN.
    • Every program returns a status code, either 0 to indicate success or a number between 1 and 255 to indicate failure. In the shell, any command is a valid boolean expression; the status code 0 is treated as true and anything else as false.
  • $(…) means run the command inside the parentheses and capture its output. So rsync is executed as soon as the shell hits the definition of the RUNSYNC variable. To store a block of shell code, use a function (example below, although you don't actually need a function here, you could just write the code directly).
  • Your test [ $APPCHK < 2 ] should be [ $APPCHK -lt 2 ]: < means input redirection. (In bash, you can also write [[ foo < bar ]], but that's string comparison, not numeric comparison.)
  • ~/ at the beginning of the remote rsync path is optional. Also, -e ssh is the default unless your version of rsync is really old.
  • exit at the end of the script is useless, the script will exit anyway.

Here's a script taking the above into account:

#!/bin/bash
 run_rsync () {
     rsync -rvz '/home/e-smith/files/ibays/drive-i/files/Warehouse Pics/organized_pics' \
           [email protected]:webapps/pavlick_container/public/images
}
process_pattern='/usr/bin/rsync -rvz /home/e-smith/files/ibays/drive-i/files/Warehouse Pics/organized_pics imgserv@192\.168\.0\.140:webapps/pavlick_container/public/images'
if pgrep -xF "$process_pattern"; then
  run_rsync
fi

Upvotes: 5

Seth Robertson
Seth Robertson

Reputation: 31471

You have a number of problems. First you are running the commands instead of putting the commands in variables. There is also a much easier way.

RUNSYNC="rsync -rvz -e ssh /home/e-smith/files/ibays/drive-i/files/Warehouse\ Pics/organized_pics  [email protected]:~/webapps/pavlick_container/public/images"
if ! pgrep -f "rsync.*organized_pics"; then $RUNSYNC; fi

Upvotes: 1

shellter
shellter

Reputation: 37318

If your real code is missing a closing dlb-quote on the grep target, you're going to get weird results from the get-go.

Also, ps aux will not list a complete command line result like you show (at least on all the the pss I have used).

You need to make it ps auxwww. Often you will see people add | grep -v grep | (you'll see why at some point). This can be reduced to changing your static search target slightly like "/usr/bin/rsync" to "/usr/bin/[r]sync ".

Other users are also helping with their comments. Using a flag file as @DiegoSevilla mentions is marginally deprecated. use a mkdir /tmp/MyWatcher_flagDir for your flag. Directory creation is an atomic activity (where as file creations are not), and this will eliminate any errors you might encounter from having 2 copies of you monitor try to make a flag file at the same time. Only one process will succeed in making or removing a flag dir.

I hope this helps.

Upvotes: 0

Diego Sevilla
Diego Sevilla

Reputation: 29021

First of all, the way of checking if the program is running is mostly wrong. This may or may not work. You should rely on some special file you create when your script starts, that it is deleted when your script ends. This will tell you if the script is running, just checking if this file exists.

Then, try to either put a \ before the ~ or to remove the ~/ completely. If cron is run as other user, the tilde will be substituted in the client for the user directory. It works for the command line because maybe the home directory of your user in both machines match, but not in the user the cron is running. A guess at this point, but again, try to remove the ~/ and see if it works.

Upvotes: 0

Rob Bailey
Rob Bailey

Reputation: 1787

Looks like with your rsync command that some directory along this path is wrong: ~/webapps/pavlick_container/public/images

Have you checked on the server 192.168.0.140 in imgserv's home directory to see if "pavlick_container/public" exists? That's my guess.

Upvotes: 1

Related Questions