【问题标题】:Python: Closing a for loop by reading stdoutPython:通过读取标准输出来关闭 for 循环
【发布时间】:2012-10-10 03:02:04
【问题描述】:
import os

dictionaryfile = "/root/john.txt"
pgpencryptedfile = "helloworld.txt.gpg"

array = open(dictionaryfile).readlines()


for x in array:
    x = x.rstrip('\n')
    newstring = "echo " + x + " | gpg --passphrase-fd 0 " + pgpencryptedfile
    os.popen(newstring)

我需要在 for 循环中创建一些东西来读取 gpg 的输出。当gpg输出这个字符串gpg: WARNING: message was not integrity protected时,我需要循环关闭并打印成功!

我该怎么做,背后的原因是什么?

谢谢大家!

【问题讨论】:

  • 您使用的是for 循环,而不是while 循环。
  • 您应该考虑使用subprocess.Popen 而不是现在已弃用的os.popen
  • 另外,gpg 是否将其写入stderrstdout
  • 我可以对 subprocess.Popen 使用相同的字符串连接吗?
  • 你有没有考虑过使用pygpgme来处理解密而不是直接调用gpg?

标签: python while-loop


【解决方案1】:
import subprocess


def check_file(dictfile, pgpfile):
    # Command to run, constructed as a list to prevent shell-escaping accidents
    cmd = ["gpg", "--passphrase-fd", "0", pgpfile]

    # Launch process, with stdin/stdout wired up to `p.stdout` and `p.stdin`
    p = subprocess.Popen(cmd, stdin = subprocess.PIPE, stdout = subprocess.PIPE)

    # Read dictfile, and send contents to stdin
    passphrase = open(dictfile).read()
    p.stdin.write(passphrase)

    # Read stdout and check for message
    stdout, stderr = p.communicate()
    for line in stdout.splitlines():
        if line.strip() == "gpg: WARNING: message was not integrity protected":
            # Relevant line was found
            return True

    # Line not found
    return False

然后使用:

not_integrity_protected = check_file("/root/john.txt", "helloworld.txt.gpg")
if not_integrity_protected:
    print "Success!"

如果 "gpg: WARNING:" 消息实际上是在 stderr 上(我怀疑是这样),请将 subprocess.Popen 行更改为:

p = subprocess.Popen(cmd, stdin = subprocess.PIPE, stderr = subprocess.PIPE)

..还有从stdoutstderr的for循环,像这样:

for line in stderr.splitlines():

【讨论】:

    【解决方案2】:

    使用subprocess.check_output 调用gpg 并根据其输出中断循环。

    类似这样的东西(未经测试,因为我对gpg一无所知):

    import subprocess
    
    dictionaryfile = "/root/john.txt"
    pgpencryptedfile = "helloworld.txt.gpg"
    
    with open(dictionaryfile, 'r') as f:
        for line in f:
            x = line.rstrip('\n')
            cmd = ["echo " + x + " | gpg --passphrase-fd 0 " + pgpencryptedfile]
            output = subprocess.check_output(cmd, shell=True)
            if 'gpg: WARNING: message was not integrity protected' in output:
                break
    

    【讨论】:

    • 我将在 Linux 上运行它,所以我不知道 cmd 是否对两个操作系统都做同样的事情。
    • Traceback(最近一次调用最后一次):文件“decrypter2.py”,第 12 行,在 中输出 = subprocess.check_output(cmd) AttributeError: 'module' object has no attribute 'check_output'
    • 这就是我现在遇到的错误。对不起,如果我听起来很愚蠢,我对编程很陌生,甚至对 python 也很陌生。
    • (你没有,但无论如何不用担心。)嗯,这似乎是说check_output 没有在subprocess 中定义。但它是...尝试打开解释器并运行import subprocess 然后subprocess.check_output(['ls']) 看看是否会出现同样的错误。
    • @user1732102 -- subprocess.check_output 在 python 版本 2.7 中添加。如果您使用的是旧版本,那就可以解释为什么您没有它。
    【解决方案3】:

    您可以使用subprocess 模块,它允许您使用:

    subprocess.call(args, *, stdin, stdout, stderr, shell)
    

    (如何使用参数请参见Python Documentation。)

    这很好,因为您可以轻松读取您调用的任何程序的退出代码。

    例如,如果您将 'newstring' 更改为:

    "echo " + x + " | gpg --passphrase-fd 0 " + pgpencryptedfile | grep 'gpg: WARNING: message was not integrity protected'
    

    grep 如果有匹配则返回 0,如果没有匹配则返回 1。 (Source)

    这个 grep 的退出代码将从 subprocess.call() 函数返回,您可以轻松地将其存储在变量中并使用 if 语句。

    编辑:正如 Matthew Adams 在下面提到的,您还可以阅读 gpg 本身的退出代码。

    【讨论】:

    • 糟糕,我刚刚从 python 文档中复制了它。我会解决的。
    • 在我更改 'newstring' 后 subprocess.call 行的外观如何?
    • 你不需要所有的参数。我认为:'subprocess.call(newstring, shell=True)' 就是你所需要的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-29
    • 2013-09-12
    相关资源
    最近更新 更多