1

I'm doing a bash script to backup my computer to a local server. I need to compress the archives but I can't find a way to make this if condition work with an ssh command inside:

if [ ssh user@192.168.1.5 '$(ls -d /snapshots/$(date -v -7d +%Y%m%d)* 2> /dev/null | wc -l) != "0"' ]
then
    ssh user@192.168.1.5 "tar -czf $ARCHIVES_DIR/$YESTERDAY.tar.gz $SNAPSHOT_DIR/$YESTERDAY* \
    && rm -rf $SNAPSHOT_DIR/$YESTERDAY*"
fi

I've got a "Too many arguments" (inside the if) error.

What am I doing wrong?

0
2

It's possible to use return status of a command as if condition, but the proper syntax is without brackets then. On the other hand, you'll need the brackets or "test" command on the remote host. (I prefer test for this.) Try this instead:

if ssh user@192.168.1.5 'test $(ls -d /snapshots/$(date -v -7d +%Y%m%d)* 2> /dev/null | wc -l) != "0"'
then
    ssh user@192.168.1.5 "tar -czf $ARCHIVES_DIR/$YESTERDAY.tar.gz $SNAPSHOT_DIR/$YESTERDAY* \
    && rm -rf $SNAPSHOT_DIR/$YESTERDAY*"
fi

You might also want to check the date command. At least on my Linux system, I got date: invalid option -- 'v'.

2
  • Thanks! The date command come from OS X, do you know what is the equivalent on linux?
    – ge0ra
    Aug 14 '15 at 14:06
  • 1
    You're trying to get date of 7 days ago? That you'll get in Linux with: date -d -7days +%Y%m%d
    – Tuomas
    Aug 14 '15 at 14:09
2

I'd suggest you simplify the construct and give the next person reading the code a chance to see what's going on. Your main issue is that you seem to be confusing your indirect execution $( ... ) with [ ... ] as a test operator. Apologies if I've misunderstood the flow, but I think this is what you intend:

# Count files on the remote system and confirm that there is at least one
DATE7=$(date -v -7d '+%Y%m%d')
NFILES=$(ssh user@192.168.1.5 "ls -d '/snapshots/$DATE7'* 2> /dev/null | wc -l")

# If the ssh worked and we have found files then archive them
if [ $? -eq 0 && 0 -lt $NFILES ]
then
    # Archive the files
    ssh user@192.168.1.5 "
        tar -czf '$ARCHIVES_DIR/$YESTERDAY.tar.gz' '$SNAPSHOT_DIR/$YESTERDAY'* &&
        rm -rf '$SNAPSHOT_DIR/$YESTERDAY'
    "
fi

This supposes that ARCHIVES_DIR, SNAPSHOT_DIR and YESTERDAY are defined locally elsewhere in your script.

Remember that "..." will interpolate variables' values immediately, whereas '...' will treat text such as $WIDGET as a literal seven character string starting with a dollar symbol. This is important to note given I have got sequences like " '...' " and ' "..." ' in this code.

1

The form if [ ... ] is a call to test: the expression within brackets is evaluated as per test's syntactic rules, and a return code is emitted, which is what if interprets. You probably want to simply get rid of the brackets:

if ssh ... | grep -q .

The command grep will return a success return code ("true" for if) if it has any successful match; in the current case, if the output from the ssh command was non-empty. A more literal translation of your original code would be:

if [ $(ssh ... | wc -l) != 0 ]

At runtime, the $(...) expression is replaced with the text output by the enclosed command; an integer, meaning that test sees a proper comparison between that integer and zero.

1

As your question is about the conditional expression only I have only tested the if-part.

You can do it this way:

if [ $(ssh user@192.168.1.5 'ls -d /snapshots/$(date -v -7d +%Y%m%d)* 2> /dev/null | wc -l') != "0" ]
then
    # do something
fi

A small addition to my answer:

You will probably have to account for not being able to make that SSH-connection also (instead of only checking for line count being non-zero).

Because if your connection fails then the result will also be "not zero".

For better error handling you could use something like this:

lines=$(ssh user@192.168.1.5 'ls -d /snapshots/$(date -v -7d +%Y%m%d)* 2> /dev/null | wc -l')
result=$?
# If 'ssh'-command succesful:
if [ $result == "0" ]
then
    # If number of lines is non-zero:
    if [ $lines != "0" ]
    then
        # do something
    fi
else
    # handle error based on $result
fi

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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