python - 如何将字符串格式应用于 bash 命令(通过子进程合并到 Python 脚本中)?

标签 python linux bash subprocess

我想在我的 Python 脚本中添加一个 bash 命令,它线性化 FASTA 序列文件,同时保持序列分离不变(因此选择了特定的命令)。以下是命令,示例输入文件为“inputfile.txt”:

awk '/^>/ {printf("\n%s\n",$0);next; } { printf("%s",$0);}  END {printf("\n");}' < inputfile.txt

目的是让用户在命令行中指定要修改的文件,例如:

$ python3 program.py inputfile.txt

我尝试将字符串格式(即 %s)与 sys.argv 结合使用以实现此目的。但是,我已经尝试了 "' 的许多不同位置,但仍然无法使其正常工作并从此处的命令行接受用户输入。 (该命令包含诸如 \n 之类的转义符,因此我试图通过添加额外的反斜杠以及现有 %s< 的额外 % 来抵消这种情况 在命令中。)

import sys
import subprocess

path = sys.argv[1]

holder = subprocess.Popen("""awk '/^>/ {printf("\\n%%s\\n",$0);next; } { printf("%%s",$0);}  END {printf("\\n");}' < %s""" % path , shell=True, stdout=subprocess.PIPE).stdout.read()

print(holder)

如果您能帮助我识别此处的语法错误,或就如何添加此用户输入提出建议,我将不胜感激。

最佳答案

TL;DR:不要花钱买 awk!只需使用 Python。但是让我们一步一步来......


您在这里使用三重引号的直觉很好,那么至少您不需要同时转义单引号和双引号,这是您在 shell 字符串中需要的。

您可以使用的下一个有用的设备是原始字符串,使用 r'...'r"..."r"""..."""。原始字符串不会扩展反斜杠转义符,因此在这种情况下您可以保持 \n 不变。

最后是 %s,如果你使用 % 运算符,你需要转义它,但在这里我建议不要使用 shell 来重定向输入,只需使用 Python 的子进程从文件发送标准输入!简单得多,你最终没有替代品。

我还建议您使用 subprocess.check_output() 而不是 Popen()。它使用起来更简单,也更健壮,因为它将检查命令是否成功退出(退出状态为零)。

将所有这些放在一起(到目前为止),您会得到:

with open(path) as inputfile:
    holder = subprocess.check_output(
        r"""awk '/^>/ {printf("\n%s\n",$0);next; } { printf("%s",$0);}  END {printf("\n");}'""",
        shell=True,
        stdin=inputfile)

但是在这里你可以更进一步,因为你真的不再需要 shell,它只是用于将命令行拆分为两个参数,所以只需在 Python 中进行拆分(这几乎总是可能且容易的这样做并且它更加健壮,因为您不必处理 shell 的分词!)

with open(path) as inputfile:
    holder = subprocess.check_output(
        ['awk', r'/^>/ {printf("\n%s\n",$0);next; } { printf("%s",$0);}  END {printf("\n");}'],
        stdin=inputfile)

列表中的第二个字符串仍然是原始字符串,因为您想保留 bacsklash 转义。

我可以探讨如何在 awk 中不使用 printf() 而是使用 print 来做到这一点,这应该摆脱 \ns 和 %s,但我会告诉你,直接用 Python 做你正在做的事情要容易得多!

事实上,awk(或 sed、tr、cut 等)可以做的所有事情,Python 都可以做得更好(或者,至少以一种更具可读性和可维护性的方式。)

对于您的特定代码:

with open(path) as inputfile:
    for line in inputfile:
        if line.startswith('>'):
            # Insert a blank line before this one.
            print()
        print(line)
        if line.startswith('>'):
            # Also insert a blank line after this.
            print()
    # And a blank line at the end.
    print()

这不是更好吗?

您可以将它放入一个函数、一个模块中,然后在任何您喜欢的地方重复使用它。很容易将结果存储在一个字符串中,如果你愿意,可以将它保存到一个变量中,更加灵活......

无论如何,如果您仍然想坚持 shelling out,请参阅我之前的代码,我认为这是您在仍然 shelling out 的同时可以做的最好的事情,而无需显着更改外部命令。

关于python - 如何将字符串格式应用于 bash 命令(通过子进程合并到 Python 脚本中)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57463917/

相关文章:

linux - 如何在ansible中获取自定义环境变量?

python - ipdb调试器,跳出循环

python - igraph 不能使用 GLPK

python - 删除空格分隔的单个字符

linux - Raspbian 上的 Mono 和 MongoDB

sql-server - 通过curl将CSV文件加载到Azure SQL仓库

linux - Bash 脚本查找和复制具有多个扩展名的文件,包括具有 2 个或 3 个扩展名的文件

没有root权限的Python音频?

python - 将默认值从 python 2.7 恢复到 python 2.6

linux - 有没有办法在两个服务器的目录之间区分 chown/chmod?