【问题标题】:Getting Output from Cisco C40 via Bash通过 Bash 从 Cisco C40 获取输出
【发布时间】:2025-08-12 15:05:01
【问题描述】:

背景

我们有一些 Cisco C40,我正在尝试通过 bash 实现自动化(尽管我愿意接受替代方案)。我需要登录它,拨一个 IP,取回返回的呼叫 ID,然后使用该 CallID 向远端发送 DTMF 音。我能够到达那里大约 90% 的路,但由于某种原因,使用 SSH 并没有返回使用交互式会话时返回的所有文本。

交互式外壳示例:

login as: admin
Using keyboard-interactive authentication.
Password:
Welcome to XXX
TANDBERG Codec Release TC7.1.1.168aadf
SW Release Date: 2014-04-11
*r Login successful

OK

xConfiguration Audio Volume: 0
** end

OK
xCommand Dial Number: FAR_END_IP

OK
*r DialResult (status=OK):
    CallId: 73
    ConferenceId: 44
** end

非交互式 Shell 示例

没有ssh -Tssh -t -t 选项

当 call-init-step1.txt 包含 xConfiguration Audio Volume: 0xCommand Dial Number: FAR_END_IP 以及要挂断的 bye 时,就会出现这种情况。

[user@controlserver C40]$ cat call-init-step1.txt | ssh admin@cisco_codec
Pseudo-terminal will not be allocated because stdin is not a terminal.
Welcome to XXX
TANDBERG Codec Release TC7.1.1.168aadf
SW Release Date: 2014-04-11
*r Login successful

OK

** end

OK

OK

我在这里缺少的是带有

的块
*r DialResult (status=OK):
    CallId: 73
    ConferenceId: 44
** end

这样我就可以将它解析为CallID,然后用它来发送下一个命令。

带有ssh -Tssh -t -t 选项

一些线程建议使用 ssh -Tssh -t -t 在这种情况下似乎没有帮助,下面是输出。

[user@controlserver C40]$ cat call-init-step1.txt | ssh -T admin@cisco_codec
Welcome to XXX
TANDBERG Codec Release TC7.1.1.168aadf
SW Release Date: 2014-04-11
*r Login successful

OK

** end

OK

OK

[user@controlserver C40]$ cat call-init-step1.txt | ssh -t -t admin@cisco_codec
Welcome to XXX
TANDBERG Codec Release TC7.1.1.168aadf
SW Release Date: 2014-04-11
*r Login successful

OK

** end

OK

OK

问题

任何有关如何获取丢失的DialResult 块的见解将不胜感激。

编辑:我还应该提到,最终命令 cat call-init-step1.txt | ssh admin@cisco_codec 将被重定向到一个文件,以便在我的脚本中进一步解析,这意味着它可能看起来像 cat call-init-step1.txt | ssh -t -t admin@cisco_codec > results.txt 然后被解析。

编辑 2:构建我正在使用 full API guide is found here 的内容

编辑 2.5:expect 的尝试

根据@MarkSetchell 的建议,我们继续编写了一个半功能性的期望脚本,如下所示:

#!/usr/bin/expect
spawn ssh admin@cisco_codec
expect "*r Login successful"
send "xConfiguration Audio Volume: 0"
expect "OK"
send "xCommand Dial Number: FAR_END_IP"
expect "** end"

结果如下:

[user@controlserver C40]$ expect expect-call
spawn ssh admin@cisco_codec
Welcome to XXX
TANDBERG Codec Release TC7.1.1.168aadf
SW Release Date: 2014-04-11
*r Login successful

OK

xConfiguration Audio Volume: 0xCommand Dial Number: FAR_END_IPxConfiguration Audio Volume: 0xCommand Dial Number: FAR_END_IP

【问题讨论】:

  • 也许是时间问题,也许你需要使用expect。只是一个想法。
  • @MarkSetchell 嗯,值得研究。我会试一试,可能需要一些时间来重新工作和测试它。
  • 好问题!你真的试图自己解决这个问题。您是否尝试过使用重定向运行,因为您指出 > results.txt ?只是为了 dbl 检查。我见过重定向文本被保存的情况,而屏幕上的文本有问题。使用cat -vet results.txt 并在行尾查找^M 字符。 那么你可能有一些工作要做;-)(只是一个想法)。祝你好运!
  • ansible 可能会给你一个更简单的方法来做到这一点
  • @shellter 我这几天确实一直在努力解决这个问题。该脚本最初进行了重定向,当我执行普通的旧 cat results.txt 时它没有出现,但我只是返回并尝试使用 cat -vet ,不幸的是这并没有成功。不过感谢您的建议!

标签: linux bash shell ssh cisco


【解决方案1】:

似乎有几种方法可以解决这个问题,如果我不得不继续使用 bash,似乎使用正确编写的 except 脚本将是可行的方法。那说有人在a Reddit post 我提出了建议的XML。我曾经想过使用 XML,但无论是我还是我必须立即帮助我的人都非常精通如何解决这个问题,但是有了incredibly helpful post,我已经在使用 Python 和 XML 的路上了。

最终产品看起来像这样:

#!/usr/bin/env python
import time
import requests
from lxml.etree import fromstring, Element, tostring


def putxml_request(xml, **kwargs):
    return requests.post(
        'http://HOSTNAME/putxml',
        auth=('USER', 'PASSWORD'),
        data=xml.format(**kwargs)).content


def xconfiguration_request(*path, **keys_and_values):
    root = Element('Configuration')
    parent = root
    for level in path:
        current = Element(level)
        parent.append(current)
        parent = current

    for k, v in keys_and_values.iteritems():
        node = Element(k)
        node.text = str(v)
        current.append(node)

    xml = tostring(root, pretty_print=True)
    return putxml_request(xml)

xconfiguration_request('Audio', Volume=0)

DIAL = '''\
<Command>
  <Dial>
    <Number>{number}</Number>
    <Protocol>{protocol}</Protocol>
  </Dial>
</Command>'''

outcome = putxml_request(
    DIAL, number='XXX', protocol='Sip')
callid = fromstring(outcome).xpath('//CallId')[0].text

# this gives it some time for the call to connect
time.sleep(10)

DTMFSEND = '''\
<Command>
  <DTMFSend>
    <CallId>{callid}</CallId>
    <DTMFString>{dtmf}</DTMFString>
  </DTMFSend>
</Command>'''
outcome = putxml_request(DTMFSEND, callid=callid, dtmf='1234')
status = fromstring(outcome).xpath('//DTMFSendResult')[0].attrib['status']

if status != 'OK':
    print('bad')
else:
    print('sent dtmf')

最终我安排了这个脚本来发起呼叫(通过 cron),然后编写了一个非常相似的脚本来使用 DisconnectAll 挂断呼叫。

我希望这对某人有所帮助,并感谢 Reddit 上的 /u/omgdave(我提供了一个机会来回答这个问题,但没有被采纳)在这方面的帮助。

【讨论】: