我用 tee 和 grep 编写了一个 linux bash 脚本来记录和时间戳我在各种 ssh session 中采取的操作。它有效,但记录的行有时会混合在一起并且充满控制字符。我怎样才能正确地转义控制和其他在原始 session 中不可见的字符并分别记录每一行?
我正在学习 bash 和 linux 界面,因此非常欢迎任何其他改进脚本的建议!
这是我的脚本(用作 ssh 命令的包装器):
#! /bin/bash
logfile=~/logs/ssh.log
desc="sshlog ${@}"
tab="\t"
format_line() {
while IFS= read -r line; do
echo -e "$(date +"%Y-%m-%d %H:%M:%S %z")${tab}${desc}${tab}${line}"
done
}
echo "[START]" | format_line >> ${logfile}
# grep is used to filter out command line output while keeping commands
ssh "$@" | tee >(grep -e '\@.*\:.*\$' --color=never --line-buffered | format_line >> ${logfile})
echo "[END]" | format_line >> ${logfile}
这是日志文件中乱码输出的屏幕截图:
关于解决方案的注释:Tiago 的回答很好地处理了非打印字符。不幸的是,我刚刚意识到困惑是由退格键和使用向上和向下键完成命令引起的。也就是说,字符一出现就被管道传输到 grep,而不是逐行。我将不得不在 another question 中询问这个问题.
更新:我figured out a way to (几乎总是)处理向上/向下完成、退格完成和控制字符。
最佳答案
您可以删除这些字符:
perl -lpe 's/[^[:print:]]//g'
未过滤:
perl -e 'for($i=0; $i<=255; $i++){print chr($i);}' | cat -A
^@^A^B^C^D^E^F^G^H^I$
^K^L^M^N^O^P^Q^R^S^T^U^V^W^X^Y^Z^[^\^]^^^_ !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~^?M-^@M-^AM-^BM-^CM-^DM-^EM-^FM-^GM-^HM-^IM-^JM-^KM-^LM-^MM-^NM-^OM-^PM-^QM-^RM-^SM-^TM-^UM-^VM-^WM-^XM-^YM-^ZM-^[M-^\M-^]M-^^M-^_M- M-!M-"M-#M-$M-%M-&M-'M-(M-)M-*M-+M-,M--M-.M-/M-0M-1M-2M-3M-4M-5M-6M-7M-8M-9M-:M-;M-<M-=M->M-?M-@M-AM-BM-CM-DM-EM-FM-GM-HM-IM-JM-KM-LM-MM-NM-OM-PM-QM-RM-SM-TM-UM-VM-WM-XM-YM-ZM-[M-\M-]M-^M-_M-`M-aM-bM-cM-dM-eM-fM-gM-hM-iM-jM-kM-lM-mM-nM-oM-pM-qM-rM-sM-tM-uM-vM-wM-xM-yM-zM-{M-|M-}M-~M-^?
过滤:
perl -e 'for($i=0; $i<=255; $i++){print chr($i);}' | perl -lpe 's/[^[:print:]]//g' | cat -A
$
!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~$
解释:
我正在打印整个 ASCII 表:
perl -e 'for($i=0; $i<=255; $i++){print chr($i);}'
我正在识别不可打印的字符:
cat -A
我正在过滤不可打印的字符:
perl -lpe 's/[^[:print:]]//g'
编辑:在我看来,您需要删除 ANSI 颜色字符:
例子:
perl -MTerm::ANSIColor -e 'print colored("yellow on_magenta","yellow on_magenta"),"\n"'| sed -r "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]//g" | perl -lpe 's/[^[:print:]]//g'
适应您的代码:
format_line() {
while IFS= read -r line; do
line=$(sed -r "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]//g" <<< "$line")
line=$(perl -lpe 's/[^[:print:]]//g' <<< "$line")
echo -e "$(date +"%Y-%m-%d %H:%M:%S %z")${tab}${desc}${tab}${line}"
done
}
我还编辑了您的 grep
命令:
ssh "$@" | tee >(grep -Po '(?<=\$).*' --color=never --line-buffered | format_line >> ${logfile})
在我的测试输出下面:
2014-06-26 10:11:10 +0100 sshlog tiago@localhost [START]
2014-06-26 10:11:15 +0100 sshlog tiago@localhost whoami
2014-06-26 10:11:16 +0100 sshlog tiago@localhost exit
2014-06-26 10:11:16 +0100 sshlog tiago@localhost [END]
关于linux - Bash:如何干净地记录 ssh/bash 输出的处理行?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24418130/