work hard
分类:
2009-11-24 13:30:36
Sometimes I want to FTP a file from one machine to another. Usually, I can do the transfer interactively, but every so often, I would like to have a shell script do the file transfer. This task has eluded me in the past, but I finally figured it out. I've not seen this particular trick documented in the past, so I submit it for your approval.
The problem I always encountered in scripting ftp transfers involved getting a password to the ftp server. Typical ftp client programs under Unix, Linux, Solaris and NetBSD all read the ftp password from /dev/tty.
#!/bin/sh
HOST='ftp.users.qwest.net'
USER='yourid'
PASSWD='yourpw'
FILE='file.txt'
ftp $HOST <user $USER
$PASSWD
put $FILE
quit
END_SCRIPT
exit 0
The above script will just hang if run in the foreground (in an xterm), or if run in the background (from a cron job), it will fail to perform the work of transferring file.txt.
/dev/tty names a strange, magic device. Each process (more strictly each process group) has a different /dev/tty, and you can not naively make ftp clients read the password from some non-magic, yet convenient source, like a "here document". When run in an xterm, the script above appears to hang because it reads the password from /dev/tty. The xterm constitutes the script's /dev/tty, so the script waits for keyboard input.
#!/bin/sh
HOST='ftp.users.qwest.net'
USER='yourid'
PASSWD='yourpw'
FILE='file.txt'
ftp -n $HOST <quote USER $USER
quote PASS $PASSWD
put $FILE
quit
END_SCRIPT
exit 0
ftp -n $HOST > /tmp/ftp.worked 2> /tmp/ftp.failed <One could further refine error handling by acting on the ftp client program's exit status:
ftp -n $HOST > /tmp/ftp.worked 2> /tmp/ftp.failed <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
Regular FTPs there and back of large files can consume a lot of time.
One obvious improvement would have the ftp client program controlled by the shell script. I don't think that would comprise an impossible task, but I also don't think that it would have much value. Scripting ftp transfer using might cause you less pain.
I saw a second way of doing this in a usenet article:
#!/bin/sh
USER=userid
PASSWD=userpw
ftp -n f2dev <