如何在一个 awk 命令中替换 .tsv 文件中的列、重新排列、包含和排除数据
How to substitute columns, rearrange, include and exclude data in a .tsv file within one awk command
我有一个 .tsv 文件,我想在其中 1/ 替换第 6 列的值,直到最后一列,2/ 排除第 4 和第 5 列,3/ 重新排列,即将第 3 列替换为第 2 列,最后在第 2 和第 3 列之间包含一个值为数字 0 的列对于所有观察(线)。
1/ 从第 6 列开始的值可以是 0,1 或 2。我想做的是:如果数字是 0,用 1\t1 代替(这样它会创建另一列).如果数字为 1,则替换为 1\t2,如果为 2,则替换为 2/t2.
我设法通过生成一个新的 .tsv 来做到这一点,其中只有第 6 列以后的值,然后使用下面 awk 中的命令:
awk '{gsub(/2/,"2\t2");}1' file.txt > file1; awk '{gsub(/1/,"1\t2");}1' file1 > file2; awk '{gsub(/0/,"1\t1");}1' file2 > file3
之后我将处理 2/ 和 3/ 问题。我将使用 awk 从原始 .tsv 文件生成一个 .tsv 文件,该文件已经排除了第 4 和第 5 列,并使用以下命令交换了第 3 和第 2 列:
awk -v OFS="\t" '{ print , , }' original_tsv_file.tsv > reordered_tsv_file.tsv
然后,下一步是将数字 0 作为新生成的第 3 列包含在内 reordered_tsv_file.tsv。我使用了以下命令:
sed -i -e 's/^/0\t/' reordered_tsv_file.tsv
这将在每个新行前面包含数字 0,现在我只需执行之前步骤中的 awk 命令,对列重新排序,如下所示:
awk -v OFS="\t" '{ print , , , }' reordered_tsv_file.tsv > final_columns_to_be_merged_with_file3.tsv
最后,为了获得我想要的文件,我只需使用以下命令粘贴 final_columns_to_be_merged_with_file3.tsv 和 file3:
paste -d'\t' final_columns_to_be_merged_with_file3.tsv file3 > final_file.tsv
下面是 original_tsv_file.tsv 的示例:
chr15 101152646 chr15:101152646:A:G A G 1 1 0 0
chr15 101152650 chr15:101152650:A:C A C 1 1 0 0
chr15 101152872 chr15:101152872:G:A G A 1 1 0 0
chr15 101152923 chr15:101152923:G:A G A 1 1 0 0
chr15 101152954 chr15:101152954:C:T C T 0 2 0 0
chr15 101153197 chr15:101153197:G:C G C 0 2 0 0
和 final_file.tsv:
chr15 chr15:101152646:A:G 0 101152646 1 2 1 2 1 1 1 1
chr15 chr15:101152650:A:C 0 101152650 1 2 1 2 1 1 1 1
chr15 chr15:101152872:G:A 0 101152872 1 2 1 2 1 1 1 1
chr15 chr15:101152923:G:A 0 101152923 1 2 1 2 1 1 1 1
chr15 chr15:101152954:C:T 0 101152954 1 1 2 2 1 1 1 1
chr15 chr15:101153197:G:C 0 101153197 1 1 2 2 1 1 1 1
我想要的是关于如何在一段代码中完成此过程而不是使用 5 个不同的命令和大量生成的文件以获得最终结果的解决方案或建议。上面的所有命令我都设法从互联网上获取并修改,但我没有;还没有改进这一点的知识。
感谢您的帮助。
你可以试试
awk 'BEGIN{OFS="\t"}
{printf "%s%s%s%s0%s%s", , OFS, , OFS, OFS, ;
for(i=6;i<=NF;++i){
if($i==0) printf OFS"1"OFS"1";
else if($i==1) printf OFS"1"OFS"2";
else printf OFS"2"OFS"2"
} printf ORS}
' original_tsv_file.tsv > final_file.tsv
你进了final_file.tsv
chr15 chr15:101152646:A:G 0 101152646 1 2 1 2 1 1 1 1
chr15 chr15:101152650:A:C 0 101152650 1 2 1 2 1 1 1 1
chr15 chr15:101152872:G:A 0 101152872 1 2 1 2 1 1 1 1
chr15 chr15:101152923:G:A 0 101152923 1 2 1 2 1 1 1 1
chr15 chr15:101152954:C:T 0 101152954 1 1 2 2 1 1 1 1
chr15 chr15:101153197:G:C 0 101153197 1 1 2 2 1 1 1 1
假设:
- OP 希望所有输出列由制表符分隔 (
\t
)(预期输出似乎是固定宽度,但 OP 的代码提到 OFS="\t"
)
- 第 6 列到 EOL 仅包含 3 个值之一:
0
或 1
或 2
一个awk
想法:
awk '
BEGIN { OFS="\t" }
{ outline= OFS OFS "0" OFS
for (i=6;i<=NF;i++)
if ($i==0) outline=outline OFS 1 OFS 1
else if ($i==1) outline=outline OFS 1 OFS 2
else outline=outline OFS 2 OFS 2
print outline
}
' file.txt
使用几个三元运算的稍微复杂的想法:
awk '
BEGIN { OFS="\t" }
{ outline= OFS OFS "0" OFS
for (i=6;i<=NF;i++)
outline=outline OFS \
(($i==0) ? 1 OFS 1 : (($i==1) ? 1 OFS 2 : 2 OFS 2))
print outline
}
' file.txt
这两个都会生成:
chr15 chr15:101152646:A:G 0 101152646 1 2 1 2 1 1 1 1
chr15 chr15:101152650:A:C 0 101152650 1 2 1 2 1 1 1 1
chr15 chr15:101152872:G:A 0 101152872 1 2 1 2 1 1 1 1
chr15 chr15:101152923:G:A 0 101152923 1 2 1 2 1 1 1 1
chr15 chr15:101152954:C:T 0 101152954 1 1 2 2 1 1 1 1
chr15 chr15:101153197:G:C 0 101153197 1 1 2 2 1 1 1 1
已经提到的第 4 列和第 5 列的要求将被丢弃,这使它们成为接收“0”和 </code> 值的额外列的完美位置。</p>
<pre><code>f='sample1.tsv'; echo; cat "${f}" | ecp; echo;
mawk2 'BEGIN { ___=length(FS="[ "(OFS="\t")"]+")
____=(__+=++__)+__
} { _=NF+=$____+= $__=substr("",($___=$__)~"")
do {
$_=(__-($_<__))"\t"(__-!$_)
} while(___<--_) } gsub("\t+","\t")' "${f}" | ecp
chr15 101152646 chr15:101152646:A:G A G 1 1 0 0
chr15 101152650 chr15:101152650:A:C A C 1 1 0 0
chr15 101152872 chr15:101152872:G:A G A 1 1 0 0
chr15 101152923 chr15:101152923:G:A G A 1 1 0 0
chr15 101152954 chr15:101152954:C:T C T 0 2 0 0
chr15 101153197 chr15:101153197:G:C G C 0 2 0 0
chr15 chr15:101152646:A:G 0 101152646 1 2 1 2 1 1 1 1
chr15 chr15:101152650:A:C 0 101152650 1 2 1 2 1 1 1 1
chr15 chr15:101152872:G:A 0 101152872 1 2 1 2 1 1 1 1
chr15 chr15:101152923:G:A 0 101152923 1 2 1 2 1 1 1 1
chr15 chr15:101152954:C:T 0 101152954 1 1 2 2 1 1 1 1
chr15 chr15:101153197:G:C 0 101153197 1 1 2 2 1 1 1 1
经测试适用于 gawk 5.1.1
(模式 -e/Pe/ce
)、mawk 1.3.4
、mawk 1.996
和 macOS nawk
。
如果您非常确定输入只有制表符作为分隔符,那么它就更简单了:
gawk 'BEGIN{ ___=index(FS="["\
(OFS="\t")"]+","]")+(__+=++__)
} { _=NF+=$(__+__)=+(\
$__=substr($___=$__,_,_<_))
do { $_=(__-($_<__) \
OFS (__-!$_)
} while(___<--_) } gsub(FS,OFS)'
— 4Chan 柜员
我有一个 .tsv 文件,我想在其中 1/ 替换第 6 列的值,直到最后一列,2/ 排除第 4 和第 5 列,3/ 重新排列,即将第 3 列替换为第 2 列,最后在第 2 和第 3 列之间包含一个值为数字 0 的列对于所有观察(线)。
1/ 从第 6 列开始的值可以是 0,1 或 2。我想做的是:如果数字是 0,用 1\t1 代替(这样它会创建另一列).如果数字为 1,则替换为 1\t2,如果为 2,则替换为 2/t2.
我设法通过生成一个新的 .tsv 来做到这一点,其中只有第 6 列以后的值,然后使用下面 awk 中的命令:
awk '{gsub(/2/,"2\t2");}1' file.txt > file1; awk '{gsub(/1/,"1\t2");}1' file1 > file2; awk '{gsub(/0/,"1\t1");}1' file2 > file3
之后我将处理 2/ 和 3/ 问题。我将使用 awk 从原始 .tsv 文件生成一个 .tsv 文件,该文件已经排除了第 4 和第 5 列,并使用以下命令交换了第 3 和第 2 列:
awk -v OFS="\t" '{ print , , }' original_tsv_file.tsv > reordered_tsv_file.tsv
然后,下一步是将数字 0 作为新生成的第 3 列包含在内 reordered_tsv_file.tsv。我使用了以下命令:
sed -i -e 's/^/0\t/' reordered_tsv_file.tsv
这将在每个新行前面包含数字 0,现在我只需执行之前步骤中的 awk 命令,对列重新排序,如下所示:
awk -v OFS="\t" '{ print , , , }' reordered_tsv_file.tsv > final_columns_to_be_merged_with_file3.tsv
最后,为了获得我想要的文件,我只需使用以下命令粘贴 final_columns_to_be_merged_with_file3.tsv 和 file3:
paste -d'\t' final_columns_to_be_merged_with_file3.tsv file3 > final_file.tsv
下面是 original_tsv_file.tsv 的示例:
chr15 101152646 chr15:101152646:A:G A G 1 1 0 0
chr15 101152650 chr15:101152650:A:C A C 1 1 0 0
chr15 101152872 chr15:101152872:G:A G A 1 1 0 0
chr15 101152923 chr15:101152923:G:A G A 1 1 0 0
chr15 101152954 chr15:101152954:C:T C T 0 2 0 0
chr15 101153197 chr15:101153197:G:C G C 0 2 0 0
和 final_file.tsv:
chr15 chr15:101152646:A:G 0 101152646 1 2 1 2 1 1 1 1
chr15 chr15:101152650:A:C 0 101152650 1 2 1 2 1 1 1 1
chr15 chr15:101152872:G:A 0 101152872 1 2 1 2 1 1 1 1
chr15 chr15:101152923:G:A 0 101152923 1 2 1 2 1 1 1 1
chr15 chr15:101152954:C:T 0 101152954 1 1 2 2 1 1 1 1
chr15 chr15:101153197:G:C 0 101153197 1 1 2 2 1 1 1 1
我想要的是关于如何在一段代码中完成此过程而不是使用 5 个不同的命令和大量生成的文件以获得最终结果的解决方案或建议。上面的所有命令我都设法从互联网上获取并修改,但我没有;还没有改进这一点的知识。
感谢您的帮助。
你可以试试
awk 'BEGIN{OFS="\t"}
{printf "%s%s%s%s0%s%s", , OFS, , OFS, OFS, ;
for(i=6;i<=NF;++i){
if($i==0) printf OFS"1"OFS"1";
else if($i==1) printf OFS"1"OFS"2";
else printf OFS"2"OFS"2"
} printf ORS}
' original_tsv_file.tsv > final_file.tsv
你进了final_file.tsv
chr15 chr15:101152646:A:G 0 101152646 1 2 1 2 1 1 1 1
chr15 chr15:101152650:A:C 0 101152650 1 2 1 2 1 1 1 1
chr15 chr15:101152872:G:A 0 101152872 1 2 1 2 1 1 1 1
chr15 chr15:101152923:G:A 0 101152923 1 2 1 2 1 1 1 1
chr15 chr15:101152954:C:T 0 101152954 1 1 2 2 1 1 1 1
chr15 chr15:101153197:G:C 0 101153197 1 1 2 2 1 1 1 1
假设:
- OP 希望所有输出列由制表符分隔 (
\t
)(预期输出似乎是固定宽度,但 OP 的代码提到OFS="\t"
) - 第 6 列到 EOL 仅包含 3 个值之一:
0
或1
或2
一个awk
想法:
awk '
BEGIN { OFS="\t" }
{ outline= OFS OFS "0" OFS
for (i=6;i<=NF;i++)
if ($i==0) outline=outline OFS 1 OFS 1
else if ($i==1) outline=outline OFS 1 OFS 2
else outline=outline OFS 2 OFS 2
print outline
}
' file.txt
使用几个三元运算的稍微复杂的想法:
awk '
BEGIN { OFS="\t" }
{ outline= OFS OFS "0" OFS
for (i=6;i<=NF;i++)
outline=outline OFS \
(($i==0) ? 1 OFS 1 : (($i==1) ? 1 OFS 2 : 2 OFS 2))
print outline
}
' file.txt
这两个都会生成:
chr15 chr15:101152646:A:G 0 101152646 1 2 1 2 1 1 1 1
chr15 chr15:101152650:A:C 0 101152650 1 2 1 2 1 1 1 1
chr15 chr15:101152872:G:A 0 101152872 1 2 1 2 1 1 1 1
chr15 chr15:101152923:G:A 0 101152923 1 2 1 2 1 1 1 1
chr15 chr15:101152954:C:T 0 101152954 1 1 2 2 1 1 1 1
chr15 chr15:101153197:G:C 0 101153197 1 1 2 2 1 1 1 1
已经提到的第 4 列和第 5 列的要求将被丢弃,这使它们成为接收“0”和 </code> 值的额外列的完美位置。</p>
<pre><code>f='sample1.tsv'; echo; cat "${f}" | ecp; echo;
mawk2 'BEGIN { ___=length(FS="[ "(OFS="\t")"]+")
____=(__+=++__)+__
} { _=NF+=$____+= $__=substr("",($___=$__)~"")
do {
$_=(__-($_<__))"\t"(__-!$_)
} while(___<--_) } gsub("\t+","\t")' "${f}" | ecp
chr15 101152646 chr15:101152646:A:G A G 1 1 0 0
chr15 101152650 chr15:101152650:A:C A C 1 1 0 0
chr15 101152872 chr15:101152872:G:A G A 1 1 0 0
chr15 101152923 chr15:101152923:G:A G A 1 1 0 0
chr15 101152954 chr15:101152954:C:T C T 0 2 0 0
chr15 101153197 chr15:101153197:G:C G C 0 2 0 0
chr15 chr15:101152646:A:G 0 101152646 1 2 1 2 1 1 1 1
chr15 chr15:101152650:A:C 0 101152650 1 2 1 2 1 1 1 1
chr15 chr15:101152872:G:A 0 101152872 1 2 1 2 1 1 1 1
chr15 chr15:101152923:G:A 0 101152923 1 2 1 2 1 1 1 1
chr15 chr15:101152954:C:T 0 101152954 1 1 2 2 1 1 1 1
chr15 chr15:101153197:G:C 0 101153197 1 1 2 2 1 1 1 1
经测试适用于 gawk 5.1.1
(模式 -e/Pe/ce
)、mawk 1.3.4
、mawk 1.996
和 macOS nawk
。
如果您非常确定输入只有制表符作为分隔符,那么它就更简单了:
gawk 'BEGIN{ ___=index(FS="["\
(OFS="\t")"]+","]")+(__+=++__)
} { _=NF+=$(__+__)=+(\
$__=substr($___=$__,_,_<_))
do { $_=(__-($_<__) \
OFS (__-!$_)
} while(___<--_) } gsub(FS,OFS)'
— 4Chan 柜员