将 SED 命令转换为 linux 命令

Posted

技术标签:

【中文标题】将 SED 命令转换为 linux 命令【英文标题】:Converting SED command to linux command 【发布时间】:2021-07-25 10:09:22 【问题描述】:

我有一个 sed 命令,它应该在 linux 上的 python 代码中运行(使用 os.system() )或转换为 python 代码。但我不知道这个 sed 命令到底是做什么的。如果您给我代码或帮助我如何在 python 中使用 os.system 实现它,我们将不胜感激,因为我在使用 os.system 时遇到了很多错误。

sed -n '1~4s/^@/>/p;2~4p' file1.fastq > file1.fasta

顺便说一句,输入和输出文件应该在我的python代码中动态定义:

seq_file1 = '6448.fastq'
input_file1 = os.path.join(sys.path[0],seq_file1)
os.system(os.path.join("sed -n '1~4s/^@/>/p;2~4p' "+ seq_file1 + ' > ' + os.path.splitext(os.path.basename(input_file1))[0]+".fasta") , shell = True)

【问题讨论】:

使用subprocess.run 和朋友,而不是os.system。引入了 subprocess 模块来缓解使用 os.system 的许多问题。 为什么不用原生python重写而不是运行外部程序呢? @9769953 问题是 subprocess.Popen 和 os.system 都无法识别字符串(sed命令)和变量的连接!你能应付吗? @Shawn 我对sed命令不熟悉,所以不知道用原生python重写它有什么作用! :( sed 显式抑制所有输出(-n),然后显式打印每 4 行,从第一行开始,将行开头的 @ 替换为 @987654330 @。然后它每第 4 行打印一次,从第 2 行开始。 【参考方案1】:

这个 sed 命令究竟做了什么?

这个sed 命令在这个文件中同时运行两个不同的操作。

-n: 抑制整个文件的输出。仅打印应用了指令p 的行。

1~4:从第 1 行开始,每 4 行应用下一条指令。

s/^@/>/p:将每个前导的@ 替换为> 并打印结果。 由于上述指令,从第 1 行开始,每 4 行应用一次。

; 操作分隔符。

2~4:从第 2 行开始每 4 行应用下一条指令。

p:打印一行。

这意味着:“在从 #1 开始的每 4 行中将前导 @ 替换为 > 并从 #2 开始每 4 行打印一次”

示例:

file1.fastq的内容:

@ line 1
@ line 2
@ line 3
@ line 4
@ line 5
@ line 6
@ line 7
@ line 8
@ line 9
@ line 10
@ line 11
@ line 12

运行sed -n '1~4s/^@/>/p;2~4p' file1.fastq > file1.fasta

file1.fasta的内容

> line 1
@ line 2
> line 5
@ line 6
> line 9
@ line 10

一个很好的参考是:http://www.gnu.org/software/sed/manual/sed.html

如何在 Python 中做同样的事情?

以下代码 sn-p 旨在说明性,因此我避免使用许多 Python 语言资源,可以应用这些资源来改进算法。

我测试了几次,它对我有用。

# import Regular Expressions module
import re

output = []

# Open the input file in read mode
with open('file1.fastq', 'r') as file_in:
    replace_step = 1 # replacement starts in line #1
    print_step = 0   # print function starts in line #2 so it bypass one step
    for i, line in enumerate(file_in):
        if replace_step == 1:
            output.append(re.sub('^@', '>', line))                        
        if replace_step >= 4:
            replace_step = 1
        else:
            replace_step += 1            

        if print_step == 1:
            output.append(line)
        if print_step >= 4:
            print_step = 1
        else:   
            print_step +=1

    print("".join(output))
    

# Open the output file in write mode
with open('file1.fasta', 'w') as file_out:
    file_out.write("".join(output))

【讨论】:

非常感谢您的详细回答。现在我可以编写自己的 sed 命令了 :) @AminJ 如果你不理解某个sed 命令,你仍然可以使用subprocess.run【参考方案2】:

你也可以使用subprocess.run:

import subprocess
 
seq_file_in = '6448.fastq'
seq_file_out = '6448_out.fastq'
with open(seq_file_out, 'w') as fw:
    subprocess.run(["sed", r"1~4s/^@/>/p;2~4p", seq_file_in], stdout=fw)

在这种情况下,当sed 命令如此简短简洁时,subprocess.run 可能会变得非常方便。

【讨论】:

以上是关于将 SED 命令转换为 linux 命令的主要内容,如果未能解决你的问题,请参考以下文章

linux中sed命令

Linux:sed工具

玩转LINUX之sed命令详解

如何用sed命令替换一行中的某个字符串

打开高效文本编辑之门_Linux Sed插入追加转换退出等命令应用

linux sed命令详解