从 telnet 会话获取日志并将相关信息写入文件但行被期望脚本中的时间戳变量覆盖

getting log from telnet session and writing relevant info to file but line gets overwritten by timestamp variable in expect script


这是我正在自动化的示例远程会话

[示例会话]

$telnet 172.16.11.2
Trying 172.16.11.2...
Connected to 172.16.11.2.
Escape character is '^]'.
BCM96858 Broadband Router
Login: user
Password: 
 > voice show
    

Global Parameters:
------------------
BoundIfName                : bronu8.2501
IP address family          : IPv4
BoundIpAddr                : 172.16.11.2
Voice Log Levels           : general=3,cmgr=3,disp=3,sipcctk=3,bos=3,ept=3,cms=3,prov=3,lhapi=3,istw=3,dsphal=3,slicslac=3
Management Protocol        : OMCI
Voice DNS Server Enable    : Off
Voice DNS Server Primary   : 0.0.0.0
Voice DNS Server Secondary : 0.0.0.0

Service Provider 0:
--------------------
   Associated Voice Profile: 1
   Locale                  : IND
   DTMFMethod              : InBand
   HookFlashMethod         : None
   DigitMap                : x+T
   Log Server Addr         : 0.0.0.0
   Log Server Port         : 0
   T38                     : on
   V18                     : on
   RTPDSCPMark             : 46
   European flash          : Off
   SIP:                       
      SIP mode             : RFC3261
      Domain               : 
      Port                 : 5060
      Transport            : UDP
      SIP URI for TLS calls: Off
      RegExpires           : 300
      RegRetryInterval     : 60
      DSCPMark             : 46
      Registrar Addr       : 172.16.11.201
      Registrar Port       : 5060
      Proxy Addr           : 172.16.11.201
      Proxy Port           : 5060
      OutBoundProxy Addr   : 172.16.11.201
      OutBoundProxy Port   : 5060
      Music Server Addr    : 0.0.0.0
      Music Server Port    : 0
      Conferencing URI     : 
      Conferencing Option  : Local
      Failover Enable      : Off
      Sip OPTIONS Enable   : Off
      Back-to-primary cfg  : Disabled
      Secondary Domain              : 
      Secondary Registrar Addr      : 0.0.0.0
      Secondary Registrar Port      : 5060
      Secondary Proxy Addr          : 0.0.0.0
      Secondary Proxy Port          : 5060
      Secondary Outbound Proxy Addr : 0.0.0.0
      Secondary Outbound Proxy Port : 5060
      To Tag Matching      : On
      Timer B ( in ms )    : 32000
      Timer F ( in ms )    : 32000
      SRTP Usage Option    : Disabled

   Account 0:
   -----------
      ActivationStatus        : Enabled
      VoipServiceStatus       : Up
      CallStatus              : Idle
      Associated LineInst     : 1
      PhysEndpt               : 0
      Extension               : 122
      DisplayName             : 
      AuthName                : 122
      AuthPwd                 : 0000
      TxGain                  : 0 dB
      RxGain                  : 0 dB
      CALLFEATURES:               
         MWI                  : off
         Caller ID number     : on
         Caller ID name       : on
         CallWaiting          : on
         CFWDNum              : 
         CallFwdAll           : off
         CallFwdBusy          : off
         CallFwdNoans         : off
         AnonymousOutgoingCall: off
         AnonymousCallRcvBlock: off
         DoNotDisturb         : off
         CallCompOnBusy       : off
         SpeedDial            : off
         WarmLine             : off
         WarmLineNum          : 
         CallBarring          : off
         CallBarringMode      : None
         CallBarringPin       : 9999
         CallBarringDigitMap  : 
         NetPrivacy           : on
      CODECSETTINGS:           
         VAD                  : on
         pTime                : 20
         CodecList            : (0) G.711MuLaw
                                (1) G.711ALaw
                                (2) G.723.1
                                (3) G.726_16
                                (4) G.726_24
                                (5) G.726_32

   Account 1:
   -----------
      ActivationStatus        : Enabled
      VoipServiceStatus       : Up
      CallStatus              : Idle
      Associated LineInst     : 2
      PhysEndpt               : 1
      Extension               : 121
      DisplayName             : 
      AuthName                : 121
      AuthPwd                 : 0000
      TxGain                  : 0 dB
      RxGain                  : 0 dB
      CALLFEATURES:               
         MWI                  : off
         Caller ID number     : on
         Caller ID name       : on
         CallWaiting          : on
         CFWDNum              : 
         CallFwdAll           : off
         CallFwdBusy          : off
         CallFwdNoans         : off
         AnonymousOutgoingCall: off
         AnonymousCallRcvBlock: off
         DoNotDisturb         : off
         CallCompOnBusy       : off
         SpeedDial            : off
         WarmLine             : off
         WarmLineNum          : 
         CallBarring          : off
         CallBarringMode      : None
         CallBarringPin       : 9999
         CallBarringDigitMap  : 
         NetPrivacy           : on
      CODECSETTINGS:           
         VAD                  : on
         pTime                : 20
         CodecList            : (0) G.711MuLaw
                                (1) G.711ALaw
                                (2) G.723.1
                                (3) G.726_16
                                (4) G.726_24
                                (5) G.726_32
 > exit

Bye bye. Have a nice day!!!
Connection closed by foreign host.

[/sample-session]

我的目标是获取包含 ActivationStatus 和 VoipServiceStatus 的行。

所以我写了这个脚本

#!/usr/bin/expect -f
set timeout 2
set ip_addr [lindex $argv 0]
set OUTFILE "voip_status.log"
spawn telnet 172.16.11.$ip_addr
expect {
  timeout { send_user "\nFailed to get login prompt for $ip_addr\n"; exit 1 }
  eof { send_user "\ntelnet failure for server $ip_addr\n"; exit 2 }
  "*Login:"
}
        #expect "*Login:"
        send -- "user\r" 
        expect "*Password:"
        send -- "user\r" 
        expect ">"
        send -- "voice show\r"
        expect ">"
        set voice_full_output $expect_out(buffer)
        set voice_stat_lines [ split $voice_full_output "\n" ]
        foreach line $voice_stat_lines {
            if {[string match "*VoipServiceStatus*" $line]} {
                set timestamp [timestamp -format %Y-%m-%d_%H:%M:%S]
                set chan [open $OUTFILE a+]
                    #puts "ok - MATCH $line"
                    puts $chan "$line $timestamp"
                close $chan
                }
            if {[string match "*ActivationStatus*" $line]} {
                set chan [open $OUTFILE a+]
                    #puts "ok - MATCH $line"
                    puts $chan "$line"
                close $chan
                }
        }
        send -- "exit\r"
expect eof

这是我的输出

$ cat voip_status.log
      ActivationStatus        : Enabled
 2021-03-17_11:32:35tus       : Up
      ActivationStatus        : Enabled
 2021-03-17_11:32:35tus       : Up

如您所见,时间戳已经覆盖了我过滤掉的行。
我希望时间戳出现在行尾。
为什么会这样?

我在这里做了一个实验设置,任何人都可以 运行 看到这种行为。
'output-voice-log-for-experiment.sh'的内容如下
[提供输入的文件]

#!/usr/bin/perl
print "
    
       Account 0:
   -----------
      ActivationStatus        : Enabled
      VoipServiceStatus       : Up
      CallStatus              : Idle
      Associated LineInst     : 1
      PhysEndpt               : 0
      Extension               : 122
      DisplayName             : 
      AuthName                : 122
      AuthPwd                 : 0000
      TxGain                  : 0 dB
      RxGain                  : 0 dB
      CALLFEATURES:               
         MWI                  : off
         Caller ID number     : on
         Caller ID name       : on
         CallWaiting          : on
         CFWDNum              : 
         CallFwdAll           : off
         CallFwdBusy          : off
         CallFwdNoans         : off
         AnonymousOutgoingCall: off
         AnonymousCallRcvBlock: off
         DoNotDisturb         : off
         CallCompOnBusy       : off
         SpeedDial            : off
         WarmLine             : off
         WarmLineNum          : 
         CallBarring          : off
         CallBarringMode      : None
         CallBarringPin       : 9999
         CallBarringDigitMap  : 
         NetPrivacy           : on
      CODECSETTINGS:           
         VAD                  : on
         pTime                : 20
         CodecList            : (0) G.711MuLaw
                                (1) G.711ALaw
                                (2) G.723.1
                                (3) G.726_16
                                (4) G.726_24
                                (5) G.726_32

   Account 1:
   -----------
      ActivationStatus        : Enabled
      VoipServiceStatus       : Up
      CallStatus              : Idle
      Associated LineInst     : 2
      PhysEndpt               : 1
      Extension               : 121
      DisplayName             : 
      AuthName                : 121
      AuthPwd                 : 0000
      TxGain                  : 0 dB
      RxGain                  : 0 dB
      CALLFEATURES:               
         MWI                  : off
         Caller ID number     : on
         Caller ID name       : on
         CallWaiting          : on
         CFWDNum              : 
         CallFwdAll           : off
         CallFwdBusy          : off
         CallFwdNoans         : off
         AnonymousOutgoingCall: off
         AnonymousCallRcvBlock: off
         DoNotDisturb         : off
         CallCompOnBusy       : off
         SpeedDial            : off
         WarmLine             : off
         WarmLineNum          : 
         CallBarring          : off
         CallBarringMode      : None
         CallBarringPin       : 9999
         CallBarringDigitMap  : 
         NetPrivacy           : on
      CODECSETTINGS:           
         VAD                  : on
         pTime                : 20
         CodecList            : (0) G.711MuLaw
                                (1) G.711ALaw
                                (2) G.723.1
                                (3) G.726_16
                                (4) G.726_24
                                (5) G.726_32
 > exit
"

[/文件提供输入]
'process-experimental-echo.sh' 的内容如下
[处理输入的文件]

#!/usr/bin/expect -f
spawn ./output-voice-log-for-experiment.sh 
    set timeout 20
    set OUTFILE "experimental_voip_status.log"
            expect ">"
            set voice_full_output $expect_out(buffer)
            set voice_stat_lines [ split $voice_full_output "\n" ]
            foreach line $voice_stat_lines {
                if {[string match "*VoipServiceStatus*" $line]} {
                    set timestamp [timestamp -format %Y-%m-%d_%H:%M:%S]
                    set chan [open $OUTFILE a+]
                        puts "ok - MATCH $line"
                        puts $chan "$line $timestamp"
                    close $chan
                    }
                if {[string match "*ActivationStatus*" $line]} {
                    set chan [open $OUTFILE a+]
                        puts "ok - MATCH $line"
                        puts $chan "$line"
                    close $chan
                    }
            }

[/文件处理输入]
现在只需 运行 ./process-experimental-echo.sh 并亲自查看此行为。
这是您将获得的输出文件

$ cat experimental_voip_status.log
      ActivationStatus        : Enabled
 2021-03-17_12:27:11tus       : Up
      ActivationStatus        : Enabled
 2021-03-17_12:27:11tus       : Up



谢谢。

如果您使用 cat -vet 查看输出文件,它会显示非打印控制字符、制表符和行尾,您会得到:

     ActivationStatus        : Enabled^M$
     VoipServiceStatus       : Up^M 2021-03-17_09:02:53$

一行中间可以看到^M,就是回车-return。在终端上,这会使光标回到行首,并开始叠印。

这是 spawn 的典型结果,它通过 pty 运行命令,将每个输出换行符更改为 carriage-return 和换行符。这是正常的,也是 pty 所希望的。您可以将其关闭(请参阅 stty -onlcr),或者知道它可能存在,您可以在脚本中将其删除:在 foreach ... 行之后,trim 变量 $line 删除 \r:

set line [string trimright $line "\r"]