3

我尝试构建在我的日志中执行一些 grep 搜索并打印结果的脚本。我尝试使用 Envoy,因为它比 subprocess 更容易,但是当我执行 grep 命令时,它会返回一个错误,即 no such file o directory。

目录结构很简单:

  • . # 脚本的根
  • test.py # 脚本文件
  • web_logs/log/ # 包含要搜索的日志的目录

我的 test.py 很简单:

import envoy

def test(value):

   search = "grep 'cv="+str(value)+"' ./web_logs/log/log_*"
   print(search) #check of the search string
   r = envoy.run(search)
   print(r.status_code, r.std_out, r.std_err)#check of the command
   response = r.std_out

if __name__ == "__main__":
   test(2)

输出是:

grep 'cv=2' ./web_logs/log/log_*
(2, '', 'grep: ./web_logs/log/log_*: No such file or directory\n')

如果我运行相同的命令:

grep 'cv=2' ./web_logs/log/log_*

我可以在日志文件中找到字符串“cv=2”的出现。

错误在哪里?

答案后更新 问题是在使用 * 时,如果不使用 glob 模块,envoy 无法爆炸,所以我按原样使用子流程,并尝试更好地研究使用 glob 模块来改进 envoy。

我使用的新代码是:

import subprocess

def test(value):

   search = "grep 'cv="+str(value)+"' ./web_logs/log/log_*"
   print(search) #check of the search string
   proc = subprocess.check_output(search, shell=True)
   print proc.split('\n')

if __name__ == "__main__":
   test(2)
4

2 回答 2

2

@baptistemm 实际上是正确的,因为您没有将 bash 作为进程的一部分运行,因此 globbing 不起作用。

然而,正在发生的事情有点深。

当您运行一个子进程时,它可以通过几个系统服务(系统调用)之一来完成。

简答 (TLDR;)

这是执行此操作的正确方法:

import envoy

def test(value):

   search = "/bin/sh -c \"grep 'cv="+str(value)+"' ./web_logs/log/log_*\""
   print(search) #check of the search string
   r = envoy.run(search)
   print(r.status_code, r.std_out, r.std_err)#check of the command
   response = r.std_out

if __name__ == "__main__":
   test(2)

将命令作为 shell 命令运行将负责通配。

长答案

每当执行子进程时,它最终都会被转换为 execve 系统调用(或等效的)。

C库中,有一些辅助函数,例如system(3)popen(3),它们execve(2)提供了更简单的执行流程的方法。system启动一个 shell 并将其参数按原样传递给 shell 的-c选项。popen 做了额外的魔法,有点像 envoy 在 python 中所做的。

在 envoy 中,参数在 envoy 代码中被解析|(参见def expand_args(command):参考资料)。然后使用等效的popen来执行进程。envoy本质上是 shell 对|标记所做的事情(将事物拆分为|然后使用 popen)。

envoy 没有*像 shell 那样进行解释,例如使用某种glob函数将其扩展为匹配文件。巴什会。因此我的回答。

一个有趣的练习是让你为 envoy 贡献代码 :-) 并让它做 globbing。

于 2016-08-21T17:34:06.633 回答
1

为什么它在终端中有效但在特使中无效与通配符有关(bash 示例)。

当您在终端中运行时

grep 'cv=2' ./web_logs/log/log_*

bash 将解析命令行并用匹配的每个文件替换星号。所以如果你有./web_logs/log/log_1 ./web_logs/log/log_2并且./web_logs/log/log_foo你的命令实际上是

grep 'cv=2' ./web_logs/log/log_1 ./web_logs/log/log_2 ./web_logs/log/log_foo

当您在 envoy 中执行相同的操作时,情况会有所不同,它不会执行文件的 globing,然后它将传递给 grep 一个名为的文件,该文件名为./web_logs/log/log_*不存在,这实际上由您粘贴的行确认你的问题。

print r.std_err
'grep: ./web_logs/log/log_*: No such file or directory\n'

ps: python有一个glob模块

于 2016-08-21T17:19:42.273 回答