Getting exit status code from 'ftp' comman

2019-02-02 16:14发布

问题:

I need to retrive the exit status code from a command line program. No worries, I used $?. But for ftp, even if it doesn't connect, it opens the ftp shell, so I'm not able to understand that the connection haven't take place.

Try this code for understand:

#!/bin/sh

ftp 1234567
OUT=$?
if [ $OUT -eq 0 ];then
   echo "ftp OK"
else
   echo "ftp Error: "$OUT
fi

exit 0

Any help? Thanks Filippo

回答1:

You should be looking for success message from ftp command rather than looking for a status. It's "226 Transfer complete". You can confirm it with ftp manual on your system.

200 PORT command successful.
150 Opening ASCII mode data connection for filename.
226 Transfer complete.
189 bytes sent in 0.145 seconds (0.8078 Kbytes/s)

Here's a sample script.

FTPLOG=/temp/ftplogfile
ftp -inv <<! > $FTPLOG
open server
user ftp pwd
put filename
close
quit
!

FTP_SUCCESS_MSG="226 Transfer complete"
if fgrep "$FTP_SUCCESS_MSG" $FTPLOG ;then
   echo "ftp OK"
else
   echo "ftp Error: "$OUT
fi
exit 0


回答2:

If you need to download something and see if the download succeeded, why don't you use wget? It supports the FTP protocol.

It will report the status of the download with several return codes (quote from man page):

EXIT STATUS
   Wget may return one of several error codes if it encounters problems.
   0   No problems occurred.
   1   Generic error code.
   2   Parse error---for instance, when parsing command-line options, the .wgetrc or .netrc...
   3   File I/O error.
   4   Network failure.
   5   SSL verification failure.
   6   Username/password authentication failure.
   7   Protocol errors.
   8   Server issued an error response.


回答3:

Try the following scripts.

To copy:

#!/bin/bash
# cftp.sh
# set -x

FTPSERVER="$1"
FTPPORT="$2"
REMOTEDIR="$3"

[[ "$REMOTEDIR" ]] || { echo -e "Usage: $0 <ftpserver> <ftpport> <remotedir> [file1] [file2] ..." > /dev/stderr ; exit 1 ; }

L=$((BASH_ARGC-3))

LOCALFILES=("${BASH_ARGV[@]:0:$L}")

RETCODE=0

for LOCALFILE in "${LOCALFILES[@]}"
do
  THISRETCODE=0
  [[ -f "$LOCALFILE" ]] || THISRETCODE=1

  LOCALDIR="$(dirname "$LOCALFILE")"
  LOCALFILENAME="$(basename "$LOCALFILE")"

  [[ $THISRETCODE = 0 ]] &&
  /usr/bin/ftp -iv "$FTPSERVER" << EOF | grep -q '226 Transfer complete' || THISRETCODE=1
    lcd $LOCALDIR
    cd $REMOTEDIR
    put $LOCALFILENAME
EOF

  RETCODE=$((RETCODE+THISRETCODE))
done

exit $RETCODE

To move:

#!/bin/bash
# mftp.sh
# set -x

FTPSERVER="$1"
FTPPORT="$2"
REMOTEDIR="$3"

[[ "$REMOTEDIR" ]] || { echo -e "Usage: $0 <ftpserver> <ftpport> <remotedir> [file1] [file2] ..." > /dev/stderr ; exit 1 ; }

L=$((BASH_ARGC-3))

LOCALFILES=("${BASH_ARGV[@]:0:$L}")

RETCODE=0

for LOCALFILE in "${LOCALFILES[@]}"
do
  THISRETCODE=0
  [[ -f "$LOCALFILE" ]] || THISRETCODE=1

  LOCALDIR="$(dirname "$LOCALFILE")"
  LOCALFILENAME="$(basename "$LOCALFILE")"

  [[ $THISRETCODE = 0 ]] &&
  /usr/bin/ftp -iv "$FTPSERVER" << EOF | grep -q '226 Transfer complete' || THISRETCODE=1
    lcd $LOCALDIR
    cd $REMOTEDIR
    put $LOCALFILENAME
EOF

  [[ $THISRETCODE = 0 ]] &&
  /bin/rm -f "$LOCALFILE" || THISRETCODE=1

  RETCODE=$((RETCODE+THISRETCODE))
done

exit $RETCODE

Here are some test cases:

For copying.

$ ./cftp.sh ; echo return code: $?
Usage: ./cftp.sh <ftpserver> <ftpport> <remotedir> [file1] [file2] ...
return code: 1
$ ./cftp.sh ftpserver 21 /mnt/disk4/d0/test ; echo return code: $?
return code: 0
$ ./cftp.sh ftpserver 21 /mnt/disk4/d0/test cftp.sh mftp.sh ; echo return code: $?
return code: 0
$ ./cftp.sh ftpserver 21 /mnt/disk4/d0/test *ftp.sh ; echo return code: $?
return code: 0
$ ./cftp.sh ftpserver 21 /mnt/disk4/d0/test cftp.s ; echo return code: $?
return code: 1
$ ./cftp.sh ftpserver 21 /mnt/disk4/d0/test cftp.s mftp.s ; echo return code: $?
return code: 2
$ ./cftp.sh ftpserver 21 /mnt/disk4/d0/tes cftp.sh ; echo return code: $?
return code: 1

For moving.

$ ./mftp.sh ftpserver 21 /mnt/disk4/d0/test cftp.sh ; echo return code: $?
/bin/rm: cannot remove `cftp.sh': Permission denied
return code: 1
$ echo foo > /tmp/bar
$ ./mftp.sh ftpserver 21 /mnt/disk4/d0/test /tmp/bar ; echo return code: $?
return code: 0
$ ls -lha /tmp/bar
ls: cannot access /tmp/bar: No such file or directory

Update: Remember to read man 5 netrc



回答4:

some scripts do -

ftp -n $HOST > /tmp/ftp.worked 2> /tmp/ftp.failed <<END_SCRIPT
blah blah
END_SCRIPT

EXITSTATUS=$?

if [ $EXITSTATUS != "0" ]
then
    # handle the error...
fi 

Except that the above doesn't always work - most FTP clients always exit with a status of 0. This leads to ugly "false negatives": the file transfer fails, but the script doesn't detect the problem.

One way to verify that a file transfer took place - transfer it back:

#!/bin/sh

ftp -n << END_SCRIPT
open $1
user $2 $3
put $4
get $4 retrieval.$$
bye
END_SCRIPT

if [ -f retrieval.$$ ]
then
    echo "FTP of $4 to $1 worked"
    rm -f retrieval.$$
else
    echo "FTP of $4 did not work"
fi


回答5:

The last time I needed to use ftp in a script, I got so frustrated with it that I finally found a BSD-licensed ftp client source and simply modified it to give it the behavior I needed, and used that instead of the version provided with the OS.

Ugly, but the depth of head-level dents in the cube wall was starting to get ridiculous



回答6:

Another way around this is to check if you have the file on your server post transfer!

Something like...

if ![ -s "$INPUT_DIR/HOP_PSA_Transactions_$BATCH_ID.csv" ]
then
    ## No Transactions file
    FAIL_TIME=`date +"%d-%m-%Y %H:%M"`
	echo "ERROR: File HOP_PSA_Transactions_$BATCH_ID.csv not found @ $FAIL_TIME" >>$LOGFILE_DIR$LOGFILE_NAME
	exit $ERR_NO_TRANS_FILE    
fi

If it's not there then it didn't transfer successfully!