使用“sed”在 TSV 文件中的字段末尾插入文本

使用“sed”在 TSV 文件中的字段末尾插入文本

我想使用sed带有通配符表达式的命令在 TSV 文件中插入字符:

我有一个这样的文件:

Marker  Pvalue  Trait   Chr Pos
S3_16887238 6.172847e-09    Total_Soil_S    3   16887238
S3_16887238 6.172847e-09    Total_Soil_Pa   3   16887238
S3_16887238 6.172847e-09    Total_Soil_Cl   3   16887238

我想_All在第三列中所有文本的末尾添加如下内容:

Marker  Pvalue  Trait   Chr Pos
S3_16887238 6.172847e-09    Total_Soil_S_All    3   16887238
S3_16887238 6.172847e-09    Total_Soil_Pa_All   3   16887238
S3_16887238 6.172847e-09    Total_Soil_Cl_All   3   16887238

我正在使用这个命令,但它不起作用:

sed -i 's/Total_Soil_\(.*\)/&_\1_All/g' top1.txt

这只是一个示例文件,可以有任何内容来代替SPaCl

答案1

我会避免使用表格数据,sed因为很难正确定位要修改的数据中的确切位置。该sed实用程序更适合处理文本等非结构化数据。


使用磨坊主mlr;专门用于处理结构化数据的工具)将字符串附加到每个 TSV 记录字段_All中的数据末尾:Trait

$ mlr --tsv put '$Trait .= "_All"' file
Marker  Pvalue  Trait   Chr     Pos
S3_16887238     6.172847e-09    Total_Soil_S_All        3       16887238
S3_16887238     6.172847e-09    Total_Soil_Pa_All       3       16887238
S3_16887238     6.172847e-09    Total_Soil_Cl_All       3       16887238

mlr与其选项一起使用-I以就地进行更改。

您是否需要确保仅当字段以 string 开头时才修改该字段Total_Soil,然后使用

mlr --tsv put '$Trait =~ "^Total_Soil" { $Trait .= "_All" }' file

使用awk,将字符串附加_All到每条记录的第三个制表符分隔字段中的数据末尾:

$ awk -F '\t' 'BEGIN { OFS=FS } NR > 1 { $3 = $3 "_All" }; 1' file
Marker  Pvalue  Trait       Chr     Pos
S3_16887238     6.172847e-09    Total_Soil_S_All        3       16887238
S3_16887238     6.172847e-09    Total_Soil_Pa_All       3       16887238
S3_16887238     6.172847e-09    Total_Soil_Cl_All       3       16887238

1代码末尾的尾随awk会导致无条件输出修改后的记录。在某种程度上,它是一种速记写作方式{ print }。请注意,我们明确需要避免修改标头。我们通过NR > 1仅在测试评估结果为时才测试使用和修改该字段来做到这一点真的NR是当前记录的序号)。

将输出重定向到新文件,然后将新文件重命名为原始名称。或者,如果您使用的是 GNU awk,请-i inplace按照说明使用在另一个问题+答案中。

同样,如果您需要确保仅修改以 string 开头的第三个字段Total_Soil,则使用

awk -F '\t' 'BEGIN { OFS=FS } NR > 1 && $3 ~ /^Total_Soil/ { $3 = $3 "_All" }; 1' file

使用 Perl 的方式与以下几乎相同awk

$ perl -F'\t' -e 'BEGIN { $" = "\t" } if ($. > 1) { $F[2] .= "_All" } print "@F"' file
Marker  Pvalue  Trait   Chr     Pos
S3_16887238     6.172847e-09    Total_Soil_S_All        3       16887238
S3_16887238     6.172847e-09    Total_Soil_Pa_All       3       16887238
S3_16887238     6.172847e-09    Total_Soil_Cl_All       3       16887238

确保我们只修改Total_Soil数据:

perl -F'\t' -e 'BEGIN { $" = "\t" } if ($. > 1 && $F[2] =~ /^Total_Soil/) { $F[2] .= "_All" } print "@F"' file

答案2

使用(以前称为 Perl_6)

~$ raku -ne 'BEGIN put get; my @a = .split("\t"); @a.[2] = @a.[2] ~ "_All"; put @a.join("\t");' file

Raku 是 Perl 编程语言家族的成员。 Raku 的一个优点是对内置 Unicode 的高级支持,不需要外部库(或特殊标志)。

上面是@Kusalananda 优秀的 Perl(5) 答案的相当直接的翻译。-ne使用Raku 的非自动打印“逐行”命令行标志。要逐字打印标题行,请使用BEGIN移相器将其put get放入(打印使用终止符)第一行get

逐行命令的主体工作方式如下:声明一个数组,并将选项卡上的my @a输入行分配给它[是] 的缩写。$_.split("\t").split("\t")$_.split("\t")

获取@a.[2]第三个元素(即列)并用相同的元素覆盖它,@a.[2] ~ "_All"并用波浪号与尾随_All字符串连接。

然后取出所有@a元素,join在选项卡上重新组合在一起,然后输出put

输入示例:

Marker  Pvalue  Trait   Chr Pos
S3_16887238 6.172847e-09    Total_Soil_S    3   16887238
S3_16887238 6.172847e-09    Total_Soil_Pa   3   16887238
S3_16887238 6.172847e-09    Total_Soil_Cl   3   16887238

示例输出:

Marker  Pvalue  Trait   Chr Pos
S3_16887238 6.172847e-09    Total_Soil_S_All    3   16887238
S3_16887238 6.172847e-09    Total_Soil_Pa_All   3   16887238
S3_16887238 6.172847e-09    Total_Soil_Cl_All   3   16887238

https://docs.raku.org
https://raku.org

答案3

使用 sed 你可以这样做:

sed 's/Total_Soil_[^[:blank:]]*/&_All/' top1.txt

要内联执行此操作,请-i在 sed 之后添加

编辑: 替换[^ ]为以[^[:blank:]]匹配除以下内容之外的所有内容空间选项卡

相关内容