Linux轮询目录FTP传输文件

  之前在公司,在linux服务器上需要写一个shell脚本,功能如下:定时任务5秒钟执行一次,轮询当前机器(127.0.0.1)A目录,并把A目录下所有QRYTYP*开头的文件传输到另外一台机器(10.32.64.128)的B目录下,文件名也为QRYTYP*。

  这样就要考虑几个问题:现在有一个文件QRYTYP123456需要传输,

  1.QRYTYP123456达到A目录下,但文件过大,还在传输。而刚好被定时任务轮询到,这样B目录下的目标文件就会不完整。

  2.假设QRYTYP123456已经传输完成,有一个定时任务轮询到文件,并且在FTP传输过程中,刚好又被第二个定时任务轮询到这个文件,导致一个文件并两个定时任务进行传输,不是我们希望看到的结果。

  3.多任务传输大文件过程中,怎么保证FTP传输是成功的?

  整个解决思路如下:

  1.使用lsof指令查看文件是否被其他进程占用

  2.如果文件没被占用,表示已传输完成,则把文件QRYTYP123456改成QRYTYPE123456.tmp,FTP传输的是QRYTYP123456.tmp文件到目标机器B的临时目录(TMP),传输完成后使用rename指令对文件进行重名并移到目标目录。

  3.为了多个任务传输同一个文件,把每个定时任务轮询到的所有QRYTYP*文件名写到file.lst.${PID_NUMBER}文件中,PID_NUMBER = [进程号][当前时间],这样保证每个任务都处理轮询到的文件,不会造成并发传输。

  4.根据ftp的传输日志,可以根据日志“226 Transfer complete”(具体日志还需根据linux的版本来定),不过一般都是已"226"开头的,所以日志里出现"226 ......",就表示该文件传输完成了。

  说了那么多,上代码最实际:

  整个模块的脚本都放在tools目录下,分别是:dgyc_crontab_second_5.sh,dgyc_main_for_cronb_second_5.sh,file_ftp2dgyc_for_crontab_second_5.sh,有几点要注意的:

  1.dgyc_crontab_second_5.sh 这个文件的执行可通过crontab -e,添加一行:* * * * * dgyc_crontab_second_5.sh,保存退出即可。

  这里是每5秒轮询一次,可以修改INTERVAL_SECOND,缩短轮询时间,最好是能被60整除,这样会比较精确。

  2.dgyc_main_for_cronb_second_5.sh:LOC_SND_DIR=/si/usr/dgyc/fsend 就是你要轮询的目录,LOC_SND_TMP=/si/usr/dgyc/tmp是用来放日志的。

  设置过滤规则FILE_NAME_FILTER_REGULATION="QRYTYP*",如果ls QRYTYP*这种通配符形式满足不了你的过滤需求,你可以通过管道"|",再使用 awk 或者 grep 的正则表达式来过滤也是可以的。

  RMT_SND_DIR,RMT_TMP_DIR都是目标机器的目录,一般都是采用"/",因为目标机器的FTP都是根据目录来开的。

  3.file_ftp2dgyc_for_crontab_second_5.sh:要修改目标机器的地址,用户名,密码。

  特别提醒:

  1.复制下面的代码到文本编辑器,换行符默认是"CRLF"的,但是linux是"LF"结尾,需要改过来的。

  2.执行文件的过程中,看看*.sh有没有"x"权限,新手常常会犯这种错误啊!!!

 

#!/bin/ksh

#if the script startuped by crontab,
#it will ececute dgyc_main_for_cronb_second_5.sh per 5 seconeds.
BASE_HOME=/tools
interval_second=5
let interval_count=60/interval_second
script_file=$BASE_HOME/dgyc_main_for_cronb_second_5.sh
for((i=1;i<=${interval_count};i++));do
  ${script_file} 2>/dev/null &
  sleep ${interval_second}
done

 

=======================================================================================================================

#
#    file directory
#
SCRIPT_DIR=/tools

#update1
LOC_SND_DIR=/si/usr/dgyc/fsend
LOC_TMP_DIR=/si/usr/dgyc/tmp
RMT_SND_DIR=/
RMT_TMP_DIR=/
CURRENT_DATE_TIME=$(date "+%Y%m%d%H%M%S")
PID_NUMBER=$$$CURRENT_DATE_TIME
TMP_FILE_SUFFIX=".tmp"
FILE_NAME_FILTER_REGULATION="QRYTYP*"

#----------------------------------------------------------------
#
#    send the txn file
#
#----------------------------------------------------------------

#
#    get the txn file list
#
cd $LOC_SND_DIR

rm -f $LOC_TMP_DIR/file.lst.$PID_NUMBER > /dev/null 2>&1
#search "QRYTYP*" file not directory and output filename
find . -maxdepth 1 -not -type d -type f -name 'QRYTYP*' -printf "%f\n" | grep -v '.tmp'$ | while read LINE
    do
        /usr/sbin/lsof |grep $LINE |grep -v lsof|grep -v grep > /dev/null 2>&1
        if [ "$?" = "1" ]
        then
            mv $LINE $LINE$TMP_FILE_SUFFIX
            echo $LINE >> $LOC_TMP_DIR/file.lst.$PID_NUMBER
            #crontab task will send a file only.
            break
        fi
    done
if [ ! -f "$LOC_TMP_DIR/file.lst.$PID_NUMBER" ] 
then 
    exit 1
fi
FILE_SIZE=`ls -l $LOC_TMP_DIR/file.lst.$PID_NUMBER | awk '{ print $5 }'`
if [ $FILE_SIZE -eq 0 ]
then
    rm -f $LOC_TMP_DIR/file.lst.$PID_NUMBER > /dev/null 2>&1
fi


#
#    get the file name and put
#
if [ "$FILE_SIZE" != "0" ]
then
    cat $LOC_TMP_DIR/file.lst.$PID_NUMBER | while read LINE
    do
        #update3
        /usr/sbin/lsof |grep $LINE$TMP_FILE_SUFFIX |grep -v lsof|grep -v grep > /dev/null 2>&1
        if [ "$?" = "1" ]
        then
            $SCRIPT_DIR/file_ftp2dgyc_for_crontab_second_5.sh $LOC_SND_DIR $LOC_TMP_DIR $LINE $RMT_SND_DIR $RMT_TMP_DIR $PID_NUMBER $TMP_FILE_SUFFIX
        fi
    done
fi
if [ -f "$LOC_TMP_DIR/file.lst.$PID_NUMBER" ]
then
    rm $LOC_TMP_DIR/file.lst.$PID_NUMBER
fi
#****************************************************************
#
#        End of file
#
#****************************************************************

=======================================================================================================================

 

#!/bin/ksh
#
#    ftp constant variable
#
FTP_ADDR=""
FTP_USER=dgyc
FTP_PWD=dgyc1113

#
#    input variable
#
LOC_SND_DIR=$1
LOC_TMP_DIR=$2
FILE_NAME=$3
RMT_SND_DIR=$4
RMT_TMP_DIR=$5
PID_NUMBER=$6
TMP_FILE_SUFFIX=$7
FTP_SUCCESS_MSG="^226 "
FTP_INFORMATION_LOG=$LOC_TMP_DIR/"ftp_information_"$PID_NUMBER".log"
#
#    check the file
#
cd $LOC_SND_DIR

ls -l $FILE_NAME$TMP_FILE_SUFFIX >/dev/null 2>&1
if [ "$?" = "1" ]
then
    exit 1
fi


#
#    copy the orignial file to a new file
#    with ".tmp" in the name.
#
TMP_FILE_NAME=$FILE_NAME$TMP_FILE_SUFFIX

#
#    put the file
#
ftp -inv $FTP_ADDR <<! >> $FTP_INFORMATION_LOG
user $FTP_USER $FTP_PWD
bin
cd $RMT_TMP_DIR
put $TMP_FILE_NAME
ls -l
rename $RMT_TMP_DIR/$TMP_FILE_NAME $RMT_SND_DIR/$FILE_NAME
close
quit
!
if grep "$FTP_SUCCESS_MSG" $FTP_INFORMATION_LOG ;then
    #if ftp transfer success,it will remove temp file 
    rm $TMP_FILE_NAME
else
    #if ftp transfer failure,it will rename temp file to file
    mv $TMP_FILE_NAME $FILE_NAME
fi

if [ -f $FTP_INFORMATION_LOG ]
then
    rm -rf $FTP_INFORMATION_LOG
fi
#****************************************************************
#
#        End of file
#
#****************************************************************

 

posted @ 2015-08-30 17:11  lizebin0918  Views(884)  Comments(0Edit  收藏  举报