【问题标题】:python: read csv, execute command and write results to new vertical columnpython:读取csv,执行命令并将结果写入新的垂直列
【发布时间】:2012-04-12 11:48:42
【问题描述】:

我对 python 完全陌生,我读过 python 的 csv 模块非常适合我想做的事情。 我花了一些时间尝试了几种不同的方法,但甚至无法使用第四(垂直)列创建数组。

我有一个包含数百行的四列 csv 文件。在我继续之前,我可能应该验证 python 甚至可以完成我想做的所有事情。

  1. 读取一个 csv 文件,
  2. 在 FILE 的第四(垂直)列上执行 COMMAND

  3. COMMAND 打印

  4. 读取每一行的 HEALTHY(来自 COMMAND)

  5. 将新的第五列上的 HEALTHY 写入 NEW_FILE 中的所有五列

  6. 循环直到 FILE 的第一个空行

示例文件(在单元格视图中以逗号分隔)

  HOST                    PLATFORM        ARCH               COMMAND
  server1                 win             x86_64             python '/root/server1.py'
  server2                 linux           x86_64             python '/root/server2.py'
  server3                 linux           x86_64             python '/root/server3.py'

示例命令

  # python '/root/server1.py'
  --------------------
  Error: Could not open /root/server1.py


  # python '/root/server2.py'
  --------------------
  server2 p1 (NTFS)       output1:100  output:200    HEALTHY:Yes
  --------------------


  # python 'root/server3.py'
  --------------------
  server3 p1 (linux)       output1:100  output:200    HEALTHY:No
  server3 p2 (linux)       output1:100  output:200    HEALTHY:Yes
  server3 p3 (swap)       output1:100  output:200    HEALTHY:No
  --------------------

如果多行 HEALTHY 且 all 不等于 Yes,则 HEALTHY 等于“No”

如果在任何行上都找不到 HEALTHY,则 HEALTHY 等于“错误扫描”

这是我目前所拥有的

  #!/usr/bin/python
  #

  import csv
  import subprocess

  # read csv file
  csv_file = open("my_list.csv", "rb")
  my_csv_reader = csv.reader(csv_file, delimiter=",")
  my_data_list = []
  for row in my_csv_reader:
          print row
          my_data_list.append(row)
  csv_file.close()

  # write csv file
  csv_file = open("new_data.csv", "wb")
  my_csv_writer = csv.writer(csv_file, delimiter=",")
  for row in my_data_list:
          my_csv_writer.writerow(row)
  csv_file.close()

  # running commands, getting output
  # run COMMAND column from csv_file, use "python 'my_script.py'" for now
  # my_script.py only for now: print "HEALTHY:Yes"
  p = subprocess.Popen("python '/root/my_script.py'",stdout=subprocess.PIPE,stderr=subprocess.PIPE)
  output, errors = p.communicate()
  print output
  print errors

执行上述:

  # python '/root/this_script.py'
  ['HOST', 'PLATFORM', 'ARCH', 'COMMAND']
  ['server1', 'win', 'x86_64', "python '/root/server1.py'"]
  ['server2', 'linux', 'x86_64', "python '/root/server2.py'"]
  ['server3', 'linux', 'x86_64', "python '/root/server3.py'"]
  Traceback (most recent call last): 
     File "thisscript.py", line 24, in ? 
       p = subprocess.Popen('python myscript1.py',stdout=subprocess.PIPE,stderr=subprocess.PIPE) 
     File "/usr/lib64/python2.4/subprocess.py", line 550, in __init__ 
       errread, errwrite) 
     File "/usr/lib64/python2.4/subprocess.py", line 993, in _execute_child 
       raise child_exception 
     OSError: [Errno 2] No such file or directory

奖励:
如果我想在标准输出/命令输出中搜索 also(例如 linux、swap、NTFS 等,--上面有问题的第三个示例命令)并将其附加到 row[5],或者在它已经搜索过 [i]Healthy[/i] 之后的下一个... /i]。

我也不知道如何使用 OR 语句。在哪里

 if 'Linux' OR 'swap' OR 'LVM' in stdout:  
     writer.writerow(row + ['Linux']) # for multiple lines/partitions.

 elif 'BSD' in stdout:  
     writer.writerow(row + ['BSD'])

 elif 'NTFS' in stdout:
     writer.writerow(row + ['Windows'])

 else:
     writer.writerow(row + ['Error Scanning'])

最后我将 COMMAND 列更改为 PATH 并修改命令以执行 PATH。哪个正在工作。我想执行第二个命令来获取 PATH 的文件大小。我尝试了几种方法。

感谢您的宝贵时间。我希望这一切都可以完成。

【问题讨论】:

  • 当您尝试该代码时会发生什么?此外,如果那是您真正的输入文件,它不是逗号分隔的,因为它没有逗号。
  • @ThomasK 我认为他只是为我们美化了 CSV。
  • 这是逗号分隔的 csv 的示例单元格视图。
  • 请编辑问题并插入输出。不要把它放在评论中。
  • 我觉得“没有任何健康 == 错误扫描”是一个不正确的断言。 “错误无法打开 == 错误扫描”,但“没有任何健康”意味着“没有错误扫描,没有发现健康”,这是我们所期望的,而不是(例如)服务器 3 有 3 次不健康的扫描,而是错误-报告“错误扫描”

标签: python csv


【解决方案1】:

您没有正确使用 subprocess.Popen,这导致了直接的问题 (OSError: [Errno 2] No such file or directory)。

一般来说,Popen 的第一个参数应该是一个序列,而不是一个字符串,除非你还传递了 shell=True 关键字参数。如果第一个参数是字符串和shell=False(默认值),Popen 将尝试执行以字符串值命名的文件。没有名为 "python '/root/my_script.py'" 的文件(整个字符串),因此您会得到一个 OSError

所以,

p = subprocess.Popen(
    "python '/root/my_script.py'", 
    stdout=subprocess.PIPE, stderr=subprocess.PIPE
)

应该会变成...

p = subprocess.Popen(
    ["python", "'/root/my_script.py'"], 
    stdout=subprocess.PIPE, stderr=subprocess.PIPE
)

或(本质上等价的)

p = subprocess.Popen(
    "python '/root/my_script.py'".split(), 
     stdout=subprocess.PIPE, stderr=subprocess.PIPE
)

或(见warning

p = subprocess.Popen(
    "python '/root/my_script.py'", shell=True,
    stdout=subprocess.PIPE, stderr=subprocess.PIPE
)

更新:您的问题的答案是肯定的。 Python 可以帮助你完成所有你想做的事情。这是您列表的细分。

剧透警告!如果您想自己解决问题,请不要阅读超出此范围的内容。

  • read a csv FILE

你做的很好。另一种方式...

with open('my_list.csv', 'rb') as fp:
    my_data_list = [row for row in csv.reader(fp)]

... 它引入了一些潜在的新概念,with statementlist comprehensions。但是您实际上并不需要一个中间列表来执行操作,您可以在同一个循环中读取和写入(见下文)

  • executes COMMAND on fourth (vertical) column of FILE
  • the COMMAND prints
  • loop until first empty row of FILE

我假设您想打印运行命令的输出或结果。

for row in my_data_list:
    command = row[3] #<- 4th column is index 3, 1st is 0
    p = Popen(command.split(), stdout=PIPE, stderr=STDOUT) #<- stderr to stdout
    stdout, empty = p.communicate()
    print stdout
  • read each line for HEALTHY (from COMMAND)
    • if multiple lines of HEALTHY and all do not equal Yes, HEALTHY equals "No"
    • if HEALTHY is not found on any lines, HEALTHY equals "Error Scanning"
  • write HEALTHY on new fifth column to NEW_FILE with all five columns

    if 'HEALTHY:No' in stdout:
        writer.writerow(row + ['No'])
    elif 'HEATHLY:Yes' in stdout:
        writer.writerow(row + ['Yes'])
    else: 
        writer.writerow(row + ['Error Scanning'])
    

把它们放在一起(未经测试)......

import csv
from subprocess import Popen, PIPE, STDOUT

with open('my_list.csv', 'rb') as incsv:
    with open('new_data.csv', 'wb') as outcsv:
        reader = csv.reader(incsv)
        writer = csv.writer(outcsv)

        for row in reader:
            p = Popen(row[3].split(), stdout=PIPE, stderr=STDOUT)
            stdout, empty = p.communicate()

            print 'Command: %s\nOutput: %s\n' % (row[3], stdout)

            if 'HEALTHY:No' in stdout:
                writer.writerow(row + ['No'])
            elif 'HEATHLY:Yes' in stdout:
                writer.writerow(row + ['Yes'])
            else: 
                writer.writerow(row + ['Error Scanning'])

更新:修复了 csv 读取器和写入器文件对象的错误命名选择

更新: Python 2.5 引入了from __future__ import with_statement 指令。对于 2.5 之前的 python 版本, with 语句不可用。在这种情况下,常见的做法是将文件操作包装在 try finally 中。比如,

import csv
from subprocess import Popen, PIPE, STDOUT

incsv = open('my_list.csv', 'rb')
try:
    reader = csv.reader(incsv)
    outcsv = open('new_data.csv', 'wb')
    try:    
        writer = csv.writer(outcsv)

        for row in reader:
            p = Popen(row[3].split(), stdout=PIPE, stderr=STDOUT)
            stdout, empty = p.communicate()

            print 'Command: %s\nOutput: %s\n' % (row[3], stdout)

            if 'HEALTHY:No' in stdout:
                writer.writerow(row + ['No'])
            elif 'HEATHLY:Yes' in stdout:
                writer.writerow(row + ['Yes'])
            else: 
                writer.writerow(row + ['Error Scanning'])
    finally:
        outcsv.close()
finally:
    incsv.close()

HTH!

【讨论】:

  • 很好,这确实解决了最后一个错误。现在打印“健康:是”
  • 我喜欢 SPOILER ALERT :) 我们需要更多这样的人,人们应该喜欢解决难题...
  • 干得好。尝试使用剧透时:文件“my_list.py”,第 4 行,open('my_list.csv', 'rb') as incsv: ^ SyntaxError: invalid syntax
  • 你用的是python 2.4还是2.5?我会更新“剧透”:)
  • 它归结为这一点,如果您使用 2.5 添加 from __future__ import with_statement 作为脚本中的第一个导入语句。如果您使用的是旧版本的 python,请参阅this previous stackoverflow question
【解决方案2】:

在您的“奖励”部分:

如果要搜索多个东西,最简单最直接的方法是分别搜索每个,然后连接or

if 'Linux' in stdout or 'swap' in stdout or 'LVM' in stdout:
    writer.writerow(row + ['Linux'])

如果你觉得这个不优雅或者需要搜索更多的东西,你可以使用any函数和一个生成器表达式

if any(x in stdout for x in ('Linux', 'swap', 'LVM')):
    writer.writerow(row + ['Linux'])

最后,如果这仍然太不优雅,或者如果标准输出变得更大并且您不想多次搜索它,您可以通过re 模块使用正则表达式。

【讨论】:

    猜你喜欢
    • 2016-01-31
    • 2022-01-08
    • 2016-03-21
    • 1970-01-01
    • 2013-10-04
    • 1970-01-01
    • 2020-06-22
    • 1970-01-01
    • 2011-11-03
    相关资源
    最近更新 更多