【问题标题】:Evaluating a remote (Paramiko) ssh command's output into a success/failure boolean将远程(Paramiko)ssh 命令的输出评估为成功/失败布尔值
【发布时间】:2020-04-21 13:24:48
【问题描述】:

我有一个检查文件是否存在的函数,它返回'True'/'False',现在我正在用eval()将它“转换”为布尔值,但我认为这不是最聪明的解决方案,但我不确定如果没有不必要的ifs,我该怎么做,

>>> foo = 'False'
>>> type(eval(foo))
<class 'bool'>
>>> type(foo)
<class 'str'>

例如,我在 ssh 连接的机器上运行这个表达式

"test -e {0} && echo True || echo False".format(self.repo)

这样,我的结果将是字符串。

def execute(command):
    (_, stdOut, _) = ssh.exec_command(command)
    output = stdOut.read()
    return output.decode('utf-8')

还有其他方法可以实现吗?

【问题讨论】:

  • shell 行没有理由回显任何内容。如果表达式为真,test -e {0}退出状态 将为 0,否则为非零(可能为 1)。测试那个
  • 不,ssh 的退出状态将是它运行的命令的退出状态。无论您使用什么来运行ssh,都将提供某种方式来访问整数退出状态。 (例如,subprocess.run(['ssh', some_host, f'test -e "{some_file}"']).returncode == 0(忽略确保 some_file 正确转义以包含在 shell 命令中的问题。)

标签: python shell ssh paramiko


【解决方案1】:

您可以使用ast.literal_eval()。这比eval() 更安全,因为它只计算文字,而不是任意表达式。

【讨论】:

  • 这个很好,我想我会用这个,我先测试一下。
  • 虽然这回答了您提出的问题,但您不应该首先使用该代码。可以直接获取退出状态,无需将退出状态转为字符串。
  • 真,虽然退出状态还是要转换的:0 =>真,非零=>假,这与Python的真性相反。
【解决方案2】:

在将文件名包含在可能被解析为代码的上下文中之前,应始终引用它。

在这里,我们使用How can you get the SSH return code using Paramiko? 中介绍的技术直接从 SSH 通道检索退出状态,而无需解析通过 stdout 传递的任何字符串。

try:
  from pipes import quote  # Python 2.x
except ImportError:
  from shlex import quote  # Python 3.x

def test_remote_existance(filename):
    # assuming that "ssh" is a paramiko SSHClient object
    command = 'test -e {0} </dev/null >/dev/null 2>&1'.format(quote(remote_file))
    chan = ssh.get_transport().open_session()
    chan.exec_command(command)
    return chan.recv_exit_status() == 0

【讨论】:

  • 坦率地说,我认为 ssh 中的一个非常严重的设计缺陷是它只传递一个字符串作为远程命令运行——如果它传递一个完整的 argv 数组,quote() 在它的调用。唉,我们已经晚了几十年来修复这个错误。
  • 您的代码将正确捕获此特定命令的退出代码,该命令不能有任何输出。但是如果该命令产生了输出,则不能直接使用 recv_exit_status,因为代码可能会死锁。您必须在等待命令完成时使用命令输出。见Paramiko ssh die/hang with big output。 – 同样对于这个特定任务,最好使用 SFTP,而不是 shell 命令。见my answer。作为副作用,这将解决所有引用问题。
【解决方案3】:

要通过 SSH 测试文件是否存在,请使用标准 API – SFTP,而不是运行 shell 命令。

使用 Paramiko,您可以通过以下方式做到这一点:

sftp = ssh.open_sftp()
try:
    sftp.stat(path)
    print("File exists")
except IOError:
    print("File does not exist or cannot be accessed")

【讨论】:

    【解决方案4】:

    在 python 中,最好的做法是返回在 python 中确定布尔值的操作,而不是执行类似的操作):

    if something:
        return True
    else:
        return False
    

    使用你的文件检查器的一个例子(这不需要被包装在一个函数中,但是为了举例:

    import os
    
    def check_file(infile):
        return os.path.isfile(infile)
    
    print(type(check_file('fun.py'))) # is true # <class 'bool'>
    print(type(check_file('nonexistent.txt'))) # is false # <class 'bool'>
    

    【讨论】:

    • 我知道这一点,但是在我的情况下,我需要在另一台机器上运行它,我已与 ssh 连接,所以我需要运行check_file(),它会返回再次字符串。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-04
    • 2022-01-08
    • 2012-06-29
    • 2011-07-31
    • 2012-11-22
    • 1970-01-01
    相关资源
    最近更新 更多