Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. It's 100% free, no registration required.

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 [email protected] '$(ls -d /snapshots/$(date -v -7d +%Y%m%d)* 2> /dev/null | wc -l) != "0"' ]
then
    ssh [email protected] "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?

share|improve this question

4 Answers 4

up vote 2 down vote accepted

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 [email protected] "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 [email protected] "
        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.

share|improve this answer

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 [email protected] 'test $(ls -d /snapshots/$(date -v -7d +%Y%m%d)* 2> /dev/null | wc -l) != "0"'
then
    ssh [email protected] "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'.

share|improve this answer
    
Thanks! The date command come from OS X, do you know what is the equivalent on linux? –  ge0ra Aug 14 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 at 14:09

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.

share|improve this answer

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

You can do it this way:

if [ $(ssh [email protected] '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 [email protected] '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
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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