I have a sub sh file which puts receives an input of local directory and path to the remote directory and sends the file to the remote directory. If the remote path is invalid the error cannot be detected.

Sample content inside the sh script:

cd $remote_dir                      <= error happens here
lcd $local_dir                      <= error did not happen so the return code resets
put a.tar

return $result

Some application calls the sh file, then the return code is used to judge if the file was successfully sent or not. If yes, the local file is backed up somewhere then deleted.

The problem is the shell returns zero even if the sending of the file failed. The file really was not copied, you can see that the error happens when you do the command manually, the path is not found is displayed in the screen, but when running as a job, it fails.

I know another way to do this is to do two steps, first check if the path exists, then output to a log file and check if the log contains an error, if there are no error then you can call the sftp put shell script. I was wondering if there is another way.

  • not entirely sure I understand the question, but wouldn't it be possible to do this in a more non-interactive way? like scp $local_dir/a.tar XXX@xxx.xxx.xxx.xxx:$remote_dir scp would then set $? properly. – azzid Mar 14 '15 at 12:21
  • This part is not a shell script, it's an sftp script. – Gilles Mar 14 '15 at 12:33
  • yeah. handling it via scp is more elegant unfortunately i have a requirement of only connecting via sftp to a server. but technically sftp is under ssh. – Nap Mar 14 '15 at 13:12

Handling errors in SFTP is a pain: the SFTP scripting language doesn't have conditional constructs; to do anything other than a predefined sequences of commands, you need to parse the output from the server after each command. You can do that with a tool like expect, but it's quite a bit of work, and it's difficult to ensure that you've covered every case.

For the sample you showed, you can use

echo "put $local_dir/a.tar $remote_dir" | sftp XXX@XXX.XXX.XXX.XXX

but in general error handling is complicated.

So don't use SFTP. Instead, mount the remote server using SSHFS. This does not require any special configuration on the server, because SSHFS uses SFTP under the hood. You only need to have FUSE working on the client.

SSHFS presents a view of the remote files as a mounted filesystem on the local machine. Thus you can use ordinary commands like cd, cp, etc. to manipulate files, without caring where each file is located (except in terms of performance — e.g. copying a file from a local location to a remote location won't go faster than your upload bandwidth).

set -e
mkdir myserver
sshfs XXX@XXX.XXX.XXX.XXX/ myserver
cp -p "$local_dir/a.tar" "myserver/$remote_dir/"
fusermount -u

Run sftp with the -b option:

sftp -b - XXX@XXX.XXX.XXX.XXX <<==
cd etc.

From the sftp manual:

-b batchfile
Batch mode reads a series of commands from an input batchfile instead of stdin. Since it lacks user interaction it should be used in conjunction with non-interactive authentication. A batchfile of ‘-’ may be used to indicate standard input. sftp will abort if any of the following commands fail: get, put, reget, reput, rename, ln, rm, mkdir, chdir, ls, lchdir, chmod, chown, chgrp, lpwd, df, symlink, and lmkdir. Termination on error can be suppressed on a command by command basis by prefixing the command with a ‘-’ character (for example, -rm /tmp/blah*).

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.