运行SCP脚本时捕获的日志中文件名被截断的原因咨询
我运行了一段bash脚本,通过scp将文件从远程服务器传输到本地服务器,并捕获scp的输出日志。使用vim查看该日志文件时,发现其中的文件名被截断,请问这是什么原因?
日志内容
bondrcpt_CEP_900_2303_2019_M04_BOND_REC_20181 0% 0 0.0KB/s --:-- ETAbondrcpt_CEP_900_2303_2019_M04_BOND_REC_20181 100% 84 1.6KB/s 00:00
bondrfnd_CEP_900_2303_2019_M06_BOND_REC_20181 0% 0 0.0KB/s --:-- ETAbondrfnd_CEP_900_2303_2019_M06_BOND_REC_20181 100% 1372 60.7KB/s 00:00
bondrcpt_CEP_900_2303_2019_M04_BOND_REC_20181 0% 0 0.0KB/s --:-- ETAbondrcpt_CEP_900_2303_2019_M04_BOND_REC_20181 100% 84 3.8KB/s 00:00
正确文件名
- bondrcpt_CEP_900_2303_2019_M04_BOND_REC_20181005_20230816_180040.TXT
- bondrfnd_CEP_900_2303_2019_M06_BOND_REC_20181231_20230814_180541.TXT
使用的bash脚本
for FILE in "${FILEMASKS[@]}"; do script -q -c "scp ${USER}@${SERVER}:${SOURCE}/${FILE}* ${DEST}" >> ${TRX_LOG} #need to REMOVE ^M from the log sed -i -e 's/\r//g' ${TRX_LOG} done
核心原因
scp输出进度时,会用**回车符(\r)**覆盖当前行来实时更新进度,而不是换行输出。你用script捕获输出追加到日志时,这些回车符导致完整文件名被后续的进度信息覆盖;虽然你用sed删除了\r,但这个操作是在scp执行完成后才运行,已经没法恢复被覆盖的完整文件名了。
另外,script命令会捕获终端的控制字符,进一步加剧了输出内容的混乱。
解决方法
方法1:关闭scp的进度输出(最简单)
给scp加-q(安静模式)参数,这样scp不会输出实时进度,只会在出错时打印信息,日志里就能保留完整的传输记录:
for FILE in "${FILEMASKS[@]}"; do scp -q ${USER}@${SERVER}:${SOURCE}/${FILE}* ${DEST} >> ${TRX_LOG} 2>&1 sed -i -e 's/\r//g' ${TRX_LOG} done
注:2>&1是把错误输出也重定向到日志,方便后续排查问题。
方法2:保留进度同时避免内容覆盖
如果需要保留进度日志,可以用awk把scp输出里的回车符替换成换行,让每一条进度信息单独占一行,避免覆盖:
for FILE in "${FILEMASKS[@]}"; do script -q -c "scp ${USER}@${SERVER}:${SOURCE}/${FILE}* ${DEST}" | awk '{sub(/\r/,"\n")}1' >> ${TRX_LOG} sed -i -e 's/\r//g' ${TRX_LOG} done
方法3:移除多余的script命令
其实不需要用script来捕获scp输出,直接重定向scp的标准输出和错误输出即可,减少终端控制字符的干扰:
for FILE in "${FILEMASKS[@]}"; do scp ${USER}@${SERVER}:${SOURCE}/${FILE}* ${DEST} >> ${TRX_LOG} 2>&1 sed -i -e 's/\r//g' ${TRX_LOG} done
内容的提问来源于stack exchange,提问作者goced

