【问题标题】:running a os.system / subprocess.call returns Syntax error [duplicate]运行 os.system / subprocess.call 返回语法错误 [重复]
【发布时间】:2019-07-29 15:28:29
【问题描述】:

我想从 Python2.7 运行这个 bash 命令:

time ( s=172.20.16 ; for i in $(seq 1 254) ; do ( ping -n -c 1 -w 1 $s.$i 1>/dev/null 2>&1 && printf "%-16s %s\n" $s.$i responded ) & done ; wait ; echo ) 

我试过这样运行它:

cmd = 'time ( s=172.20.16 ; for i in $(seq 1 254) ; do ( ping -n -c 1 -w 1 $s.$i 1>/dev/null 2>&1 && printf "%-16s %s\n" $s.$i responded ) & done ; wait ; echo )'

#1. subprocess.call(cmd.split())
#2. subprocess.call(cmd, shell=True)
#3. os.system(cmd)

但全部返回 /bin/sh: 1: Syntax error: word unexpected (expecting ")"),而从 bash 运行它时运行良好。我还尝试在命令的头部添加/bin/bash,但没有奏效。

当使用os.system('bash "{}"'.format(cmd)) 时,它并没有因上一个错误而崩溃,但循环不正确地展开(它打印了 1..254 而不是使用它们作为 IP 后缀)

我设法通过将命令保存在 bash 脚本中然后从 python 调用脚本来使其工作,但我宁愿直接这样做。这里有什么问题?

【问题讨论】:

  • 您对cmd 的分配甚至不是有效的Python。
  • time 是一个 bash 内置函数。不能保证在其他 shell 中会/做您期望的事情,特别是包括/bin/sh
  • @CharlesDuffy 在验证这是我与which time 一起使用的time 之后,我也尝试使用/usr/bin/time
  • @CIsForCookies, /usr/bin/time 有不同的语法。您不能像使用内置命令那样将复合命令传递给它。 (另一方面,您可以使用['time', 'sh', '-c', cmd];这样您就可以向它传递一个简单的命令,sh)。
  • 另外,which time 在这种情况下完全没用/毫无意义; which 甚至不知道 shell 函数、内置函数或别名存在。如果您想知道您在 bash 中使用的time 的实现,您需要type time,而不是which time

标签: python bash python-2.7


【解决方案1】:

shell=True 使用/bin/sh/bin/sh 不是 bash

保留 shell 脚本的所有问题,但使用 bash 调用它,如下所示:

cmd = 'time ( s=172.20.16 ; for i in $(seq 1 254) ; do ( ping -n -c 1 -w 1 $s.$i 1>/dev/null 2>&1 && printf "%-16s %s\n" $s.$i responded ) & done ; wait ; echo )'
subprocess.call(['bash', '-c', cmd])

重写它实际上是一个更好的 shell 脚本可能看起来像:

cmd = r'''
time {
  s=172.20.16
  for ((i=1; i<=254; i++)); do
    { ping -n -c 1 -w 1 "$s.$i" >/dev/null 2>&1 && \
      printf "%-16s %s\n" "$s.$i" "responded"
    } &
  done
  wait
  echo
}
'''
subprocess.call(['bash', '-c', cmd])

请注意,我们使用{ ...; },而不是( ... ) 进行分组(从而避免创建不必要的子shell);并且我们总是引用替换。

【讨论】:

  • 我正在使用你的答案,但现在我遇到了另一件事......分配给x = subprocess.check_output(...) 的输出是'\n' 即使我得到更多的输出行,但不知何故滑倒了远离x
  • 这些行真的是输出,还是在stderr上?
  • ...如果您想合并这两个流,请将stderr=subprocess.STDOUT 作为单独的关键字参数添加到subprocess.call()
  • 是的...我只是为了检查您之前的评论。当然我看到的输出实际上是stderr。谢谢!!
【解决方案2】:

尝试按照此链接使用子进程Running Bash commands in Python

import subprocess
subprocess.call("{}".format(cmd).split())

【讨论】:

  • split()不管你是否使用subprocess都是一个问题。
  • 很高兴知道。需要详细说明吗?
  • 如果没有shell=Trueargs 参数到subprocess.call 的预期格式是一个列表,每个 argv 值有一个条目。使用string.split() 生成该列表适用于非常简单的情况,例如ls hello.txt,但它会将ls "Hello World.txt" 更改为['ls', '"Hello', 'World.txt"']。对于需要 shell 来连接它们的复合命令,即使使用 shell-syntax-aware 替换(如 shlex.split())也会出现错误,并且确实需要重写以让 shell 进行拆分,或者以本机方式连接进程蟒蛇。
  • 这是有道理的。谢谢。
【解决方案3】:

您正在按空间拆分以构造 suprocess 调用方法的命令/参数数组;但请注意,有些参数包含空格,所以它应该算作一个参数,而不是两个(即这个:"%-16s %s\n"

【讨论】:

  • 没有解释所有情况,所以我认为这不是主要问题
  • 对,Charles Duffy 的回答解决了第二种情况。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-04
  • 1970-01-01
  • 1970-01-01
  • 2014-11-18
  • 2019-03-23
  • 2013-01-17
相关资源
最近更新 更多