多台机器比对抽取SFTP数据至hdfs_shell脚本简易版

当SFTP中数据量过大时,一台机器可能抽取不过来,可以利用多台机器抽取,该shell脚本实现的功能有:

  1. 多台机器比对已下载文件和sftp中文件,下载没有下载过的文件
  2. 多台机器不需要通信,简化布置难度
  3. 将下载到的大量小文件合并后,将“前缀-日期....”命名的文件上传到hdfs对应的日期目录下
  4. 记录下载的文件名、文件大小、文件数量和合并后的文件数量、文件大小 
  5. 需要用到except组件,请单独安装,except组件可离线安装,请字行百度
#!/bin/bash
#/home/data/script/cmp_getfile.sh
source ~/.bash_profile
shopt -s expand_aliases

#
# 比对上传ftp文件 
# 当文件在ftp里存在已下载文件中时,从ftp下载文件到hdfs 
#
# 参数: ftp路径 本地文件存放地址 hdfs路径 hive表名 命名前缀 机器总数 下载序列
# ./cmp_get_file.sh /data/sftp/N10 /home/data/5G/SA /user/test/n10_hdfs test_5g_n10 N10-Anhui 4 0
#需要配置的参数 script_path
#下载序列为(0到机器数减一),每台机器不可重复 
#共有多少台机器下载 
#    程序会根据文件名,计算md5值,取前3位数值,除以机器总数,根据余数是否等于下载序列值 
#    来确定是否下载该文件 
#


#脚本所在目录
script_path='/home/data/script/'
#机器数 
jc_nums=$6

#=========================
m_ftpip='sftpname@sftpip'
m_pwd='xxxxxx'
m_ftp_path=$1
m_local_ptah=$2
m_hdfs_path=$3
m_hive_name=$4
m_file_pre=$5
id=$7
#对id做简单校验 
if [ ${id:--1} -lt 0 -o ${id:--1} -ge $jc_nums ];then
    echo 'parameters error!!'
    exit 1
fi
#临时日志文件存放地址 
log_path_tmp="${script_path}/tmp_logs"
#下载文件记录存放地址 
file_info_path="${script_path}/file_logs"
#上传文件记录存放地市 ##重要 从ftp上记录下载不在该记录的数据  
down_list_path="${script_path}/config"

[ ! -d ${log_path_tmp} ] && mkdir -p ${log_path_tmp}
[ ! -d ${file_info_path} ] && mkdir -p ${file_info_path}
[ ! -d ${down_list_path} ] && mkdir -p ${down_list_path}
down_list="${down_list_path}/${m_file_pre}_downlist.list"
time_falg=`date +"%F %T"`
time_falg_s=`date +%s`
#今天和昨天时间  
tday=`date +%Y%m%d`
yday=`date +%Y%m%d -d "$tday -1 day"`
echo "[${time_falg}]  =================== script is running "

#本次流程需要下载的文件列表 
x_time=`date +%Y%m%d%H%M`
re_path=${log_path_tmp}/${x_time}_${m_file_pre}_filelist.list
#本次流程实际下载的文件列表 
re_path1=${log_path_tmp}/${x_time}_${m_file_pre}_downlist.list

#ftp 存放文件目录 
#函数参数(4个参数): ftp路径 hdfs上传路径 下载文件存放本地地址 
# ex:  get_file_list /data/sftp/N10 /user/test/n10_hdfs /home/data/5G/SA

function get_file_list(){
    if [ $# -ne 4 ];then
        echo '[ERROR] get_file_list error!'
        return 1
    fi
    #ftp ip 地址 
    ftpip=$1
    #ftp 路径 
    ftp_tmp=$2
    #hdfs路径 
    hdfs_path=$3
    #下载文件存放路径 
    file_ptah_tmp=$4/${x_time:-0}
    #判断下载路径是否存在
    if [ ! -d "${4:=0}" ];then 
        echo 'ERROR : download path not exists!!'
        exit 1
    fi  
    log_path_fd=${log_path_tmp}/${x_time}_${m_file_pre}_ftpfile.list
    log_path_hd=${log_path_tmp}/${x_time}_${m_file_pre}_hdfsfile.list
    file_list=${file_info_path}/${m_file_pre}_file_list.list
    
    #获取ftp文件列表 
#开头不能有空格 
#5G数据sftp上传文件成功后会生成一个ok文件,根据ok文件来抽取数据 
expect << EOF | sed 's/\x0d//g' | awk '$9 ~ /txt\.ok/{print $9}' | sort | sed 's/txt.ok/txt.gz/g'>${log_path_fd}
set timeout 600
spawn sftp ${m_ftpip}
expect "password:"
send "${m_pwd}\r"
expect "sftp>"
send "cd ${ftp_tmp}/${yday}\r"
expect "sftp>"
send "ls -lt ${m_file_pre}-*ok\r"
send "cd ${ftp_tmp}/${tday}\r"
expect "sftp>"
send "ls -lt ${m_file_pre}-*ok\r"
expect "sftp>"
send "quit\r"
expect eof
EOF


    #获取hdfs文件列表 --默认有天级和小时级
    #hadoop fs -ls ${hdfs_path}/${yday}/*/ ${hdfs_path}/${tday}/*/ 2>/dev/null | grep '^-.*txt.*' | awk -F ' ' '{split($8,tA,"/");print tA[length(tA)]}' | sort >${log_path_hd}
    #获取已下载文件列表 
    cat ${down_list} ${log_path_tmp}/*_${m_file_pre}_filelist.list 2>/dev/null | sort -u >${log_path_hd}
    #获取需要下载文件列表
    # re_path
    grep -f ${log_path_hd} -vxF ${log_path_fd} \
    | awk '{cmd1="echo -n "$1" | md5sum";
            filename=$1;
            cmd1 | getline;
            md5str=substr($1,0,3);
            close(cmd1);
            x=strtonum("0x"md5str)%'$jc_nums';
            if(x=='$id'){print filename}}' >${re_path}

    rm -f ${log_path_hd:-0}
    rm -f ${log_path_fd:-0}
    
    #拼接下载文件命令  
    #拼接下载文件 
    yday_cmd_str=''
    for file_name in `cat ${re_path} | grep ".*-.*-${yday}.*-.*-"`;do
        
        yday_cmd_str="${yday_cmd_str}
expect \"sftp>\"
send \"get ${file_name}\\r\""
    done
    
    tday_cmd_str=''
    for file_name in `cat ${re_path} | grep ".*-.*-${tday}.*-.*-"`;do
       tday_cmd_str="${tday_cmd_str}
expect \"sftp>\"
send \"get ${file_name}\\r\""
    done

    
    #拼接完整sftp 下载命令 
    ftp_getfile_cmd="expect << EOF 2>&1 | grep -v '^sftp>' | grep -v '^Fetching'
set timeout 600
spawn sftp ${m_ftpip}
expect \"password:\"
send \"${m_pwd}\\r\"
expect \"sftp>\"
send \"progress\\r\"
"
    #昨天未下载文件 
    if [ "$yday_cmd_str" != '' ];then
        ftp_getfile_cmd="$ftp_getfile_cmd
expect \"sftp>\"
send \"cd ${ftp_tmp}/${yday}\\r\"
${yday_cmd_str}
"
    fi
    #今天未下载文件 
    if [ "$tday_cmd_str" != '' ];then 
        ftp_getfile_cmd="$ftp_getfile_cmd
expect \"sftp>\"
send \"cd ${ftp_tmp}/${tday}\\r\"
${tday_cmd_str}"
    fi

    ftp_getfile_cmd="$ftp_getfile_cmd
expect \"sftp>\"
send \"quit\\r\"
expect eof
EOF"
    
    #备份下载命令 
    #echo "${ftp_getfile_cmd}" >get_cmd.list
    #执行下载命令 
    gf_time_s=`date +%s`
    [ ! -d ${file_ptah_tmp} ] && mkdir -p ${file_ptah_tmp}
    cd ${file_ptah_tmp}
    eval "${ftp_getfile_cmd}" 
    
    #统计下载文件信息 
    re_path1=${log_path_tmp}/${x_time}_${m_file_pre}_downlist.list
    ls -l ${m_file_pre}-*-*-*.txt* 2>/dev/null | awk '$9 ~ /txt\.gz/{print $9"|"$5}' >${re_path1}
    re_get_file_nums=`cat ${re_path1} | wc -l`
    #应该下载文件总大小 
    total_size=0
    #应该下载文件各时段信息 
    re_msg='#'
    for day_time in `awk -F '-' '{print substr($3,1,8)}' ${re_path1} | sort -u`;do
        day_files=0
        day_size=0
        for name_size in `grep ".*-.*-${day_time}.*-.*-" ${re_path1} `;do 
            let day_files++
            tmp_size=`echo "${name_size}" | cut -d '|' -f 2`
            tmp_size=${tmp_size:=0} 
            let day_size=day_size+tmp_size
        done 
        re_msg="${re_msg}
# [${time_falg}]  ${day_time} : ${day_files} ${day_size}"
        let total_size=total_size+day_size
    done
    echo "# [${time_falg}]"'  ======== total files : '${re_get_file_nums}'  total size : '${total_size}'  ========' >>${file_list}
    cat <<EOF >>${file_list}
${re_msg}

EOF
    
    gf_time_e=`date +%s`
    #输出日志下载时间 
    echo "[${time_falg}]  get file time : "`expr $gf_time_e - $gf_time_s`
    echo "[${time_falg}]  get file nums : "$re_get_file_nums
    echo "[${time_falg}]  get file size : "$total_size
    
}


#上传文件函数 
#参数 : 本地文件存放地址 hdfs路径 hive表名(暂时用不到) 
function put_file() {
    pf_time_s=`date +%s`
    tmp_time=`date +"%F %T"`
    #本地文件存放地址 
    tmp_path=${1}/${x_time:-0}
    #hdfs路径 
    put_hdfs_path=$2
    #hive表名 
    hive_name=$3
    
    #判断下载路径是否存在
    if [ ! -d "${tmp_path}" ];then 
        echo 'ERROR : download path not exists!! '$tmp_path
        exit 1
    fi    
    
    cd ${tmp_path}
    #压缩后的文件数 
    file_nums=0
    file_size=0
    
    #上传文件 --数据量暂时过小 小时级分区不启用 默认00分区
    #小时级分区
    #re_msg 日志信息     
    re_msg='#' 
    for file_time in `ls ${m_file_pre}-*-*-*.txt* 2>/dev/null | sed 's/.*-.*-\([0-9]\{10\}\)[0-9]\{4\}-.*-.*/\1/' | sort | uniq`;do
        tmp_file_size=0
    #小时级分区 
    #for file_time in `ls ${m_file_pre}-*-*-*.txt* 2>/dev/null | sed 's/.*-.*-.*-\([0-9]\{10\}\)[0-9]\{4\}-.*/\1/' | sort | uniq`;do
        #文件合并 128M以上 一个文件 134217728
        size_128m=134217728
        #该时间段的文件名和大小 
        tmp_file_strs=`ls -l ${m_file_pre}-${file_time}*-*.txt.gz 2>/dev/null | awk '$9 ~ /txt\.gz/{print $9"|"$5}'`
        hh_files=0
        hh_size=0
        for tmp_file_name in $tmp_file_strs;do
            
            tmp_file=`echo ${tmp_file_name} | cut -d '|' -f 1`
            file_size2=`echo ${tmp_file_name} | cut -d '|' -f 2`
            #时间段数据量 
            let hh_files=hh_files+1
            let hh_size=hh_size+${file_size2:=0}
            #总数据量
            let file_size=file_size+file_size2
            if [ $tmp_file_size -eq 0 ];then 
               meger_file=$tmp_file
               let file_nums=file_nums+1
               let tmp_file_size=tmp_file_size+file_size2
               continue
            fi
            if [ $file_size2 -gt $size_128m ];then 
               let file_nums=file_nums+1
               continue
            fi
            cat ${tmp_file} >>${meger_file:-0}
            rm -f ${tmp_file:-0}
            if [ $tmp_file_size -gt $size_128m ];then 
                tmp_file_size=0
            fi

        done
        re_msg="${re_msg}
# [${time_falg}]  ${file_time} : files-${hh_files} size-${hh_size}"

        
        file_day=${file_time:0:8}
        file_hh=${file_time:8:2}
        
        #判断上传路径是否存在 
        if ! hadoop fs -test -e ${put_hdfs_path}/${file_day}/${file_hh};then 
            echo 'ERROR : upload path not exists!! ' ${put_hdfs_path}/${file_day}/${file_hh}
            rm -f ${m_file_pre}-${file_time}*-*.txt*
            continue
        fi 
           
        hadoop fs -put -f ${m_file_pre}-${file_time}*-*.txt.gz ${put_hdfs_path}/${file_day}/${file_hh}/
        #上传成功将下载文件写入下载列表 
        if [ $? -eq 0 ];then 
           grep "${m_file_pre}-${file_time}.*-.*.txt.gz" ${re_path1} >>${file_list}
           grep "${m_file_pre}-${file_time}.*-.*.txt.gz" ${re_path1} | awk -F '|' '{print $1}' >>${down_list}
        else 
           echo '[ERROR] put files to hdfs error! '"${m_file_pre}-${file_time}*-*.txt.gz"  >>${file_list}
        fi
        rm -f ${m_file_pre}-${file_time}*-*.txt*
    done 
    #日志信息 文件数 
    cat <<EOF >>${file_list}
${re_msg}

EOF
    #删除已下载文件列表里不属于今天和昨天的文件 
    sed -i '/'${tday}'\|'${yday}'/!d' ${down_list}
    #判断tmp_path参数长度,防止误删  
    cd -
    if [ "${#tmp_path}" -gt 20 ];then 
        rm -rf ${tmp_path:-0}
    fi
    pf_time_e=`date +%s`
    echo "[${time_falg}]  put megerfile nums : ${file_nums}"
    echo "[${time_falg}]  put mergerfile size : ${file_size}"
    echo "[${time_falg}]  put file time : "`expr $pf_time_e - $pf_time_s`
}

get_file_list "$m_ftpip" "$m_ftp_path" "$m_hdfs_path" "$m_local_ptah"
time_flag_2=`date +%s`
put_file "$m_local_ptah" "$m_hdfs_path" "$m_hive_name"

rm -f ${re_path:-0}
rm -f ${re_path1:-0}
time_flag_e=`date +%s`

#脚本执行时长 
total_times=`expr $time_flag_e - $time_falg_s`

#时长超过一小时则告警
if [ $total_times -gt 3600 ];then
    /data/script/5g_sendMsg.sh "$m_file_pre" "$total_times" "${time_falg}"
    #/data/script/send_msg.sh '156xxxxxxxx' "XX XX $m_file_pre脚本执行时间超过1小时,请注意!! [000.00.00.000]"
fi
echo "[${time_falg}]  script total time : "$total_times
echo "[${time_falg}]  get_file_list time : "`expr $time_flag_2 - $time_falg_s`
echo "[${time_falg}]  put_file time : "`expr $time_flag_e - $time_flag_2`
echo "[${time_falg}]  =================== script is over "

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值