【问题标题】:bash/awk: remove duplicate columns after merging of several filesbash/awk:合并多个文件后删除重复的列
【发布时间】:2021-04-19 12:51:56
【问题描述】:

我正在使用我的 bash 脚本中编写的以下函数,以便将许多文件(包含多列数据)合并到一个包含所有融合数据的大摘要图表中

table_fuse () {   
    paste -d'\t' "${rescore}"/*.csv >> "${rescore}"/results_2PROTS_CNE_strategy3.csv | column -t -s$'\t'
}

以两个文件为例,该例程会产生如下的拼接图作为合并的结果:

# file 1.                   # file 2
Lig dG(10V1) dG(rmsd)   Lig dG(10V2) dG(rmsd)
lig1 -6.78 0.32 lig1 -7.04 0.20
lig2 -5.56 0.14 lig2 -5.79 0.45
lig3 -7.30 0.78 lig3 -7.28 0.71
lig4 -7.98 0.44 lig4 -7.87 0.42
lig5 -6.78 0.28 lig5 -6.75 0.31
lig6 -6.24 0.24 lig6 -6.24 0.24
lig7 -7.44 0.40 lig7 -7.42 0.39
lig8 -4.62 0.41 lig8 -5.19 0.11
lig9 -7.26 0.16 lig9 -7.30 0.13

由于两个文件共享相同的第一列(Lig),如何在每个 fused 文件中删除(替换为“”)该列的所有重复,同时只保留第一列的 Lig 列CSV?

【问题讨论】:

  • 你说你有代码从所有后续文件中添加 Lig 列,同时合并它们并询问如何删除它。考虑一开始就不要添加它。顺便说一句,您的函数将不起作用 - 您正在将命令的输出重定向到文件,然后尝试将该重定向的结果通过管道传输到 column

标签: bash awk multiple-columns


【解决方案1】:

编辑:根据 OP 的 cmets 来覆盖文件中的 [Ll]ig[Ll]ig0123[Ll]ig(abcd) 格式,在此处添加以下解决方案。

awk '{first=$1;gsub(/[Ll]ig([0-9]+)?(\([-azA-Z]+\))?/,"");print first,$0}'  Input_file


考虑到您只想删除 lig(digits) 此处的重复值,您可以尝试使用 awk

awk '{first=$1;gsub(/[Ll]ig([0-9]+)?/,"");print first,$0}' Input_file

说明:为上述添加详细说明。

awk '                   ##Starting awk program from here.
{
  first=$1              ##Setting first column value to first here.
  gsub(/[Ll]ig([0-9]+)?/,"")  ##Globally substituting L/lig digits(optional) with NULL in whole line.
  print first,$0        ##printing first and current line here.
}
' Input_file            ##mentioning Input_file name here.

【讨论】:

  • 谢谢!实际上它完成了这项工作,但也跳过了标题的名称(LIG)。也能去掉吗?我还注意到它在文件开头添加了额外的一列(LIG),因此合并后的文件在(在单元格 A 和 B 中)包含 2 个 LIGS 列,其中一个包含数据(没问题!),另一个为空。 .
  • @HotJAMS,好的,我已经编辑了我的代码来处理 lig OR Lig,还在 Lig/lig 之后设置了可选的数字,以便它现在也处理标题值,请检查它并告诉我如果这对你有帮助。
  • 谢谢!事实上,我需要完全删除第一列的标题,即 Lig(CNE),所以当前版本将其保留为 (CNE),我想 AWK 中的这个 RE 应该进一步修改以匹配这个模式:-)
  • 好的,再次感谢您!只有一个问题 - (作为一个潜在的错误)这个 AWK 解决方案可能会在删除未使用的列的同时改变 LINES 的顺序吗??
  • @HotJAMS,行的顺序不会改变(考虑到您只在最终合并的文件上运行它),请告诉我是否可以用这个awk '{first=$1;gsub(/[Ll]ig([0-9]+)?(\([-azA-Z]+\))?/,"");print first,$0}' Input_file 编辑我的答案一次?为了让未来的读者也能从中受益,让我知道干杯。
【解决方案2】:

替换重复的短语并不难。适合您的情况的具体方法取决于精确的输入文件格式;但是像

sed s/^\([^ ]*\)\( .* \)\1 /\1\2 /' file

将删除第一列中标记的任何重复。

不过,也许更好的解决方案是使用更复杂的合并工具。一个简单的 Awk 或 Python 脚本可以在合并时从每个文件中删除第一个标记,但第一个标记除外。

【讨论】:

  • 好的,谢谢!是的,实际上这是合并数据的唯一方法,我可以找到并适应我的数据。如果您有任何进一步的想法,我将不胜感激......
  • 一个简单的 Awk 脚本从一组打开的文件句柄中读取一行并合并它们将很容易编写,但对于大量输入文件来说不是特别健壮。典型的限制是大约 25 个文件。应该不难找到例子。
  • unix.stackexchange.com/questions/98945/a-better-paste-command 有一个解决方案,对文件数量没有限制,但缺点是文件需要放入内存中。
【解决方案3】:

join 似乎是一个解决方案,至少对于 OP 提供的示例数据而言...

示例输入数据:

$ cat file1
Lig dG(10V1) dG(rmsd)
lig1 -6.78 0.32
lig2 -5.56 0.14
lig3 -7.30 0.78
lig4 -7.98 0.44
lig5 -6.78 0.28
lig6 -6.24 0.24
lig7 -7.44 0.40
lig8 -4.62 0.41
lig9 -7.26 0.16

$ cat file2
Lig dG(10V2) dG(rmsd)
lig1 -7.04 0.20
lig2 -5.79 0.45
lig3 -7.28 0.71
lig4 -7.87 0.42
lig5 -6.75 0.31
lig6 -6.24 0.24
lig7 -7.42 0.39
lig8 -5.19 0.11
lig9 -7.30 0.13

我们可以join这两个文件放在第一列(又名字段),如下所示:

$  join -j1 file1 file2
Lig dG(10V1) dG(rmsd) dG(10V2) dG(rmsd)
lig1 -6.78 0.32 -7.04 0.20
lig2 -5.56 0.14 -5.79 0.45
lig3 -7.30 0.78 -7.28 0.71
lig4 -7.98 0.44 -7.87 0.42
lig5 -6.78 0.28 -6.75 0.31
lig6 -6.24 0.24 -6.24 0.24
lig7 -7.44 0.40 -7.42 0.39
lig8 -4.62 0.41 -5.19 0.11
lig9 -7.26 0.16 -7.30 0.13

对于超过 2 个文件,将需要某种重复/循环方法来重复将新文件加入到混合中。

【讨论】:

  • 我试过这样:join -j1 "${directory_with_all_csvs}"/*.csv > merge.csv。它没有用:-)
  • 看答案的最后一句话; join 一次处理 2 个文件;在linux join more than 2 files 上进行谷歌搜索会出现多个点击,例如join more than 2 files
  • 我知道它可以正常工作,只合并两个填充。谢谢!
猜你喜欢
  • 1970-01-01
  • 2013-05-28
  • 2012-06-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-25
  • 2020-05-18
  • 1970-01-01
相关资源
最近更新 更多