【问题标题】:Execute df | grep -w "/" not parsing output correctly执行 df | grep -w "/" 没有正确解析输出
【发布时间】:2022-01-21 03:36:51
【问题描述】:

我正在尝试使用 python 运行 shell 命令 df -h | grep -w "/" 以观察根分区的使用情况,并希望避免使用 shell=True 选项以确保安全。

我尝试的代码如下:

import subprocess
p1 = subprocess.Popen(['df', '-h'], stdout=subprocess.PIPE)
p2 = subprocess.Popen(['grep', '-w', '"/"'], stdin=p1.stdout, stdout=subprocess.PIPE)
output=p2.communicate()[0]
print(output)

我得到的输出是:

$ ./subprocess_df_check.py 
b''

预期输出是:

$ df -h | grep -w "/"
/dev/sdd        251G  4.9G  234G   3% /

【问题讨论】:

  • 我认为 grep 可能正在寻找文字模式 "/" 包括引号。尝试去掉双引号。反正你不需要它们,因为 / 不是 shell 特殊字符。
  • 太好了,这就是问题所在。但现在输出打印为(b'/dev/sdd 251G 4.9G 234G 3% /\n', None)。你如何从输出中删除那些额外的“b”、“\n”、“无”的东西?
  • 'grep', '-w', '/' -- 双引号用于外壳,而不是df。当你没有 shell 时,你不需要 shell 语法。
  • @JohnW,如果你还有括号和None,这意味着你的真实代码没有[0],所以你打印的是(stdout, stderr)元组,而不仅仅是标准输出。使您的代码与您在问题中显示的内容相匹配,您就不会遇到这个问题。 (至于b'',我们在知识库中有数百个已经回答的问题:这意味着你有一个字节字符串而不是一个Unicode字符串)。

标签: python python-3.x subprocess


【解决方案1】:

直接的问题是添加了不必要的引号。

p2 = subprocess.Popen(['grep', '-w', '"/"'], stdin=p1.stdout, stdout=subprocess.PIPE)

等同于 shell 命令grep -w "/"。相反,它等效于 shell 命令grep -w '"/"',(或grep -w \"/\",或任何其他编写参数向量的方法,该方法在grep 的参数向量的最后一个非NUL 元素上传递文字双引号字符)和错误的原因相同。

使用'/',而不是'"/"'

【讨论】:

    【解决方案2】:

    不要将子进程与df 和/或grep 一起使用。如果您已经使用 python,您可以使用 statvfs 函数调用,如:

    import os
    import time
    
    path = "/"
    
    while True:
        info = os.statvfs(path)
        print("Block size [%d]  Free blocks [%d]  Free inodes [%d]"
              % (info.f_bsize, info.f_bfree, info.f_ffree))
        time.sleep(15)
    

    【讨论】:

      【解决方案3】:

      在单独的子进程中运行grep 肯定是没有必要的。如果您使用的是 Python,那么您已经拥有了一个出色的工具来查找字符串中的子字符串。

      df = subprocess.run(['df', '-h'],
          capture_output=True, text=True, check=True)
      for line in df.stdout.split('\n')[1:]:
          if '/' in line:
              print(line)
      

      还请注意,您基本上总是希望在可能的情况下更喜欢subprocess.run 而不是Popen,以及您希望text=True 获取文本而不是bytes。通常您还希望check=True 确保子进程成功完成。

      【讨论】:

      【解决方案4】:

      好的,搞清楚了整个事情。

      import subprocess
      p1 = subprocess.Popen(['df', '-h'], stdout=subprocess.PIPE)
      p2 = subprocess.Popen(['grep', '-w', '/'], stdin=p1.stdout, stdout=subprocess.PIPE)
      output=p2.communicate()[0].split()[4]
      print("Root partition is of", output.decode(), "usage now")
      
      • 删除了不必要的双引号,从subprocess.Popen(['grep', '-w', '"/"'] 更改为subprocess.Popen(['grep', '-w', '/']。双引号用于 shell,而不是 df。如果没有 shell,就不需要 shell 语法。
      • output=p2.communicate()[0].split()[4] 上,[0] 只选择标准输出,而不是标准错误,如果没有错误,标准错误是None。然后split()[4] 从 shell df 命令中删除第 4 列,即磁盘使用百分比值。
      • output.decode()decode()是对编码后的字节字符串格式进行解码,避免在结果前面输出字符b。参考here

      所以脚本的输出是:

      $ ./subprocess_df_check.py
      Root partition is of 3% usage now
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-05-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多