我有一个文件A.tsv
(字段分隔符 = \t
):
for Research Use Only
[Header]
Test Name Il
Run ID 2102
Run Date 2021-02-04
Report Date/Time 2021-02-05 08:48
Instrument Serial
Flow Cell ID
Software Version
[Quality Control]
Lane 1,2,3,4 PASS
Lane 1,2,3,4 Index Set 1 PASS
[Patient Sample Results]
Sample ID Internal Control Result Consensus Sequence Lane Index Set Index ID
207 Pass Not Available 1,2,3,4 1 UDP0001
205 Pass Not Available 1,2,3,4 1 UDP0002
[Control Sample Results]
Sample ID Control Type Human Control SARS-CoV-2 Lane Index Set Index ID
CONTROL-POS Positive Control Not Detected Detected 1,2,3,4 1 UDP0008
我只想在新文件中打印这些行:
Sample ID Internal Control Result Consensus Sequence Lane Index Set Index ID
207 Pass Not Available 1,2,3,4 1 UDP0001
205 Pass Not Available 1,2,3,4 1 UDP0002
CONTROL-POS Positive Control Not Detected Detected 1,2,3,4 1 UDP0008
所以我想打印[Patient Sample Results]
and之后的行[Control Sample Results]
,但只打印标题行一次。
该文件是子采样,不能使用行号对其进行硬编码。
所以我尝试了类似的东西:
awk '/Patient Sample Results/{getline; print}' A.tsv > data_info.tsv
但它只打印第一个模式之后的行。你有办法解决我的问题吗?
答案1
假设您的[ ... ]
部分由空行分隔(其中不得包含空格/制表符),并且您想要打印以 开头的所有部分的内容[Patient Sample Results]
,以下应该可以工作:
awk -F"\n" -v RS="" '$1~/^\[Patient Sample Results\]/{s=2}
s{for (i=s;i<=NF;i++) print $i; s=3}' A.tsv > data_info.tsv
这将指示awk
在“段落模式”下操作,将任何空行组视为记录分隔符,将换行符视为字段分隔符。
“章节标题”现在将显示为
$1
记录的第一个“字段”( )。一旦第一个字段(=行)或记录以 开头
[Patient Sample Results]
,我们设置一个标志s
来2
指示- 我们想要从现在开始打印结果,并且
- 我们想要(最初)打印从第二行(=字段)开始因为第一次我们要打印“标题”行。
注意我使用正则表达式比较
$1 ~
而不是完整字符串比较$1==
来防止可能的尾随空格/制表符。如果
s
设置,则打印以 number 开头的字段(=行)s
,该字段最初为 2。然后,将其设置为 3,以便我们将来跳过“标题”行。
由于字段(=行)“按原样”打印,因此这将保留输入文件中找到的分隔符。
如果您的部分由实际包含空格的“空”行分隔,以下修改需要 GNUawk
进行多字符记录分隔符,将防止这种情况发生(请参阅@EdMorton 在 StackOverflow 上的回答例如):
awk -F'\n' -v RS='\n(([[:space:]]*\n)+|$)' ' ... '
这会将任意数量的“完全空或仅包含空白字符的行”作为记录分隔符。
答案2
也许像
awk 'BEGIN {FS="\t"}
/^\[Patient Sample Results]/ { printing=1 ; next }
!printing { next }
/^\[/ { next }
/^[ \t]*$/ { next }
/^Sample/ { if (!printedheader) { print }; printedheader=1 ; next }
{ print }'
- 设置字段分隔符为tab,实际不需要
- 请注意我们何时必须开始打印
- 如果我们尚未打印,则跳到下一行
- 不要打印以以下内容开头的行
[
- 跳过空白行,仅定义为空格和制表符。
- 如果这是标题,请在第一次看到它时打印它,然后跳到下一行。
- 打印剩余的内容
写得尽可能明显,而不是使用 awk 习惯用法,例如1
代替{ print }
.
编辑。更改空行的定义以响应评论。
答案3
尝试:
awk '/\[(Patient|Control) Sample Results\]/{ hdr++; next }
hdr==2 { hdr--; next }
hdr && !rep { print; rep=1; next }
rep && $0!="" { print }
' infile
答案4
使用GNU sed
我们可以执行以下操作,无论配置文件 A.tsv 中列出的是患者还是对照样本结果,顺序都无关紧要
sed -En '
/\[(Patient|Control) Sample Results]/,/^\s*$/{
//!{p;d;}
/\S/!d;n;G
/\n./n;P;h
}
' A.tsv
一些术语:在一系列行中,/begin/,/end/
第一个和最后一个是该范围的边界框,可以通过//
正则表达式访问。同样,内部也可通过 访问//!
。前提是这是我们在输入范围时使用的第一个正则表达式。