在 python 子进程 popen 中格式化命令

Formatting a command in python subprocess popen

我正在尝试格式化以下 awk 命令

awk -v OFS="\t" '{printf "chr%s\t%s\t%s\n", , -1, }' file1.txt > file2.txt

用于 python 子进程 popen。但是我很难格式化它。我尝试过类似答案中建议的解决方案,但其中 none 有效。我也尝试过使用原始字符串文字。我也不想使用 shell=True 因为不推荐使用

根据评论编辑: 我尝试的命令是

awk_command = """awk -v OFS="\t" '{printf "chr%s\t%s\t%s\n", , -1, }' file1.txt > file2.txt"""
command_execute = Popen(shlex.split(awk_command))

但是我在执行此操作时收到以下错误

KeyError: 'printf "chr%s\t%s\t%s\n", , -1, '

谷歌搜索错误表明当为未定义的键请求值时会发生这种情况,但我在这里不理解它的上下文

  1. 最简单的方法,特别是如果你想保留输出重定向的东西,就是使用 subprocessshell=True - 那么你只需要转义 Python 特殊的角色。该行作为一个整体,将被默认解释为 shell.

    • 警告:请勿在未先清理的情况下将其用于不受信任的输入!
  2. 或者,您可以将命令行替换为 argv 类型的序列,并将其提供给 subprocess。然后,您需要提供程序会看到的内容:

    • 删除所有shell级转义
    • 删除输出重定向内容并改为自己进行重定向

关于具体问题:

  • 你没有转义字符串中的 Python 特殊字符,所以 \t\n 变成了文字制表符和换行符(尝试 print awk_command
  • 使用 shlex.splitshell=True 没有什么不同 - 增加了不可靠性,因为它不能保证是否会像 shell 一样解析字符串每种情况(更不用说缺少 shell 所做的转换)。

    • 具体来说,不知道也不关心重定向部分的特殊含义:

      >>> awk_command = """awk -v OFS="\t" '{printf "chr%s\t%s\t%s\n", , - 1, }' file1.txt > file2.txt"""
      >>> shlex.split(awk_command)
      ['awk','-v','OFS=\t','{printf "chr%s\t%s\t%s\n", , -1, }','file1.txt','>','file2.txt']
      

因此,如果您想使用 shell=False,请自行构建参数列表。

> 是 shell 重定向运算符。要在 Python 中实现它,请使用 stdout 参数:

#!/usr/bin/env python
import shlex
import subprocess

cmd = r"""awk -v OFS="\t" '{printf "chr%s\t%s\t%s\n", , -1, }'"""
with open('file2.txt', 'wb', 0) as output_file:
    subprocess.check_call(shlex.split(cmd) + ["file1.txt"], stdout=output_file)

为避免启动单独的进程,您可以在纯 Python.

中实现此特定的 awk 命令