python-3.x - 通过带有显式引号的子进程发送多个管道命令

标签 python-3.x shell subprocess pipe popen

我一直在尝试通过 subprocess 执行管道命令模块,但我遇到了一些问题。

我已经看到了下面提出的解决方案,但没有一个解决了我的问题:
- sending a sequence (list) of arguments
- several Popen commands using subprocess.PIPE
- sending a string with shell=True

我想避免第三种选择,shell=True ,尽管它确实在我的测试系统上产生了预期的结果。

这是在终端中工作的命令,我想复制它:

tr -c "[:alpha:]" " " < some\ file\ name_raw.txt | sed -E "s/ +/ /g" | tr "[:upper:]" "[:lower:]" > clean_in_one_command.txt

此命令根据需要清理文件。它首先使用 tr输入文件上的命令,该文件的名称中有空格。输出传递给 sed ,它会删除一些空格,然后将内容传递给 tr再次使所有内容小写。

经过几次迭代,我最终将其分解为最简单的形式,实现了上面的第二种方法:Popen 的几个实例, 使用 subprocess.PIPE 传递信息.它是冗长的,但有望使调试更容易:
from subprocess import run, Popen, PIPE

cmd1_func = ['tr']
cmd1_flags = ['-c']
cmd1_arg1 = [r'"[:alpha:]\"']
cmd1_arg2 = [r'" "']
cmd1_pass_input = ['<']
cmd1_infile = ['some file name_raw.txt']
cmd1 = cmd1_func + cmd1_flags + cmd1_arg1 + cmd1_arg2 + cmd1_pass_input + cmd1_infile
print("Command 1:", cmd1)    # just to see if things look fine

cmd2_func = ['sed']
cmd2_flags = ['-E']
cmd2_arg = [r'"s/ +/ /g\"']
cmd2 = cmd2_func + cmd2_flags + cmd2_arg
print("command 2:", cmd2)

cmd3_func = ['tr']
cmd3_arg1 = ["\"[:upper:]\""]
cmd3_arg2 = ["\"[:lower:]\""]
cmd3_pass_output = ['>']
cmd3_outfile = [output_file_abs]
cmd3 = cmd3_func + cmd3_arg1 + cmd3_arg2 + cmd3_pass_output + cmd3_outfile
print("command 3:", cmd3)

# run first command into first process
proc1, _ = Popen(cmd1, stdout=PIPE)
# pass its output as input to second process
proc2, _ = Popen(cmd2, stdin=proc1.stdout, stdout=PIPE)
# close first process
proc1.stdout.close()
# output of second process into third process
proc3, _ = Popen(cmd3, stdin=proc2.stdout, stdout=PIPE)
# close second process output
proc2.stdout.close()
# save any output from final process to a logger
output = proc3.communicate()[0]

然后我会简单地将输出写入文本文件,但程序并没有那么远,因为我收到以下错误:
usage: tr [-Ccsu] string1 string2
       tr [-Ccu] -d string1
       tr [-Ccu] -s string1
       tr [-Ccu] -ds string1 string2
sed: 1: ""s/ +/ /g\"": invalid command code "
usage: tr [-Ccsu] string1 string2
       tr [-Ccu] -d string1
       tr [-Ccu] -s string1
       tr [-Ccu] -ds string1 string2

这表明我的论点没有正确传递。似乎 '"引号都被传递到 sed" .我确实确实需要其中一个。如果我只将一组放入我的列表中,那么它们会在命令中被完全剥离,这也会破坏命令。

我尝试过的事情:
  • 不为那些需要显式引号的字符串声明文字字符串
  • 转义和双重转义显式引用
  • 将整个命令作为一个列表传递到 subprocess.Popensubprocess.run职能。
  • 玩弄 shlex 包处理报价
  • 拆卸零件 cmd3_pass_output = ['>']cmd3_outfile= [output_file_abs]以便只处理原始(管道)输出。

  • 我是否遗漏了什么,或者我将被迫使用 shell=True ?

    最佳答案

    这个程序似乎做你想做的事。每个进程都必须单独运行。当您构建它们时,一个的输出将通过管道输出到下一个的输入。这些文件是独立处理的,并在流程的开始和结束时使用。

    #! /usr/bin/env python3
    import subprocess
    
    
    def main():
        with open('raw.txt', 'r') as stdin, open('clean.txt', 'w') as stdout:
            step_1 = subprocess.Popen(
                ('tr', '-c', '[:alpha:]', ' '),
                stdin=stdin,
                stdout=subprocess.PIPE
            )
            step_2 = subprocess.Popen(
                ('sed', '-E', 's/ +/ /g'),
                stdin=step_1.stdout,
                stdout=subprocess.PIPE
            )
            step_3 = subprocess.Popen(
                ('tr', '[:upper:]', '[:lower:]'),
                stdin=step_2.stdout,
                stdout=stdout
            )
            step_3.wait()
    
    
    if __name__ == '__main__':
        main()
    

    关于python-3.x - 通过带有显式引号的子进程发送多个管道命令,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42997967/

    相关文章:

    python - 当我在 Bash 中有一系列命令时,如何重定向标准输入/标准输出?

    python - SVM sklearn verbose 仅​​显示点

    python - 将键值字典对应用于数据框中的多列

    python - 避免将重复项添加到存储在数据库中的列表的更好方法是什么

    linux - 在 shell 脚本中计算平均值时如何处理缺失值?

    shell - sh shell中的自解压脚本

    python - Seaborn BarPlot 反转 y 轴并将 x 轴保持在图表区域的底部

    Php/Perl/Python/Shell 脚本根据某些字符的存在来重命名文件

    python - 在 Python 脚本中使用 sudo

    python - 如何使用子流程获取动态行?