添加具有来自不同文件的部分匹配模式的列
Add a column with partially matching pattern from a different file
我有两个结构相似的文件(制表符分隔和很多很多行,第 3 列减去第 2 列 = 1)看起来有点像这样:
文件 1:
1 170023 170024 A -
1 170024 170025 T -
1 170026 170027 A -
1 170028 170029 G -
1 170029 170030 C -
1 170031 170032 C -
文件 2:
1 170023 170024 A
1 170024 170025 T
1 170025 170026 G
1 170026 170027 A
1 170027 170028 G
1 170028 170029 T
1 170029 170030 A
1 170030 170031 G
1 170031 170032 C
我想将文件 2 的第 4 列(仅字母列)添加到文件 1。通常,使用 pr
或 paste
会很容易,但问题是两个文件中的第 1-3 列不同。换句话说,文件的行数不同,文件 2 的行数总是比文件 1 多(特别是,文件 1 中第 2 列和第 3 列中的所有数字也出现在文件 2 中,但 vice相反)。我也知道如何在 R 中执行此操作,但文件太大而无法在 R 中轻松处理,我将需要为十几个文件完成任务。所以我想,bash 或任何命令行软件将是解决此问题的最有效方法。
当且仅当文件 2 中的第 1-3 列与文件 1 中的第 1-3 列完全匹配时,我真正想要做的是添加文件 2 中第 4 列的字母。因此,文件 1 的第 4 列和第 5 列中出现什么符号并不重要。根据上面文件 1 和文件 2 的示例,所需的输出将是:
输出:
1 170023 170024 A - A
1 170024 170025 T - T
1 170026 170027 A - A
1 170028 170029 G - T
1 170029 170030 C - A
1 170031 170032 C - C
如果有人能帮助我,我将非常高兴。非常感谢您!
我可以考虑并提供一个使用 join
和 awk
的简单解决方案。用 awk
可能不是解决它的最有效方法(可能会为此遭到专家的抨击 :)),但我能够解决这个问题。
解法-1:-
您需要做的就是首先使用 join
而不指定任何特定的列来加入。它会根据常见的重复列(在本例中为第 1 列)自动连接文件。然后在该输出上,我们可以让 awk
播放以打印符合您需要的那些行并格式化所需的列。
join file1 file2 | awk '{ if ((==) && (==)) printf("%s %s %s %s %s %s\n", , , , , , ) }'
为我生成的输出为
1 170023 170024 A - A
1 170024 170025 T - T
1 170026 170027 A - A
1 170028 170029 G - T
1 170029 170030 C - A
1 170031 170032 C - C
解法-2:-
仅使用普通 join
join -j 2 file1 file2 -o 1.1,1.2,1.3,1.4,1.5,2.4
也会产生与您预期相同的输出。
`join' writes to standard output a line for each pair of input lines that have identical join fields.
我引用 join
的 man
页面内容如下
`-j FIELD'
Equivalent to `-1 FIELD -2 FIELD'.
`-o FIELD-LIST'
Otherwise, construct each output line according to the format in
FIELD-LIST. Each element in FIELD-LIST is either the single
character `0' or has the form M.N where the file number, M, is `1'
or `2' and N is a positive field number.
因此该命令首先通过第 2 列连接 file1
和 file2
并打印所见输出中所需的列,由 (1.1
,1.2
表示,1.3
,1.4
,1.5
,2.4
) 应读作 file
.column
。为了更好地理解,我建议先查看不带 -o
选项的输出,以及我如何根据所见构建输出。
解法-3:-
使用plain'ol awk
,其实我自己在回答这个问题的时候也学到了一些。
awk 'FNR==NR{a[ FS FS ]=;next} (( FS FS ) in a) {print [=15=], a[ FS FS ]}' file2 file1
解释:-
FNR==NR{a[ FS FS ]=;next}
将处理 file2
存储数组 a
的条目,下标为 column1 space column2 space column3值为 column4.
现在 file1
,我们需要通过执行 (( FS FS ) in a) {print [=41=], a[ FS FS ]}
来匹配数组中 file2
的那些行,这将给我所有这些行(我们需要file1
中 column4) 的值,其下标与 file2
.
中的下标相同
我有两个结构相似的文件(制表符分隔和很多很多行,第 3 列减去第 2 列 = 1)看起来有点像这样:
文件 1:
1 170023 170024 A -
1 170024 170025 T -
1 170026 170027 A -
1 170028 170029 G -
1 170029 170030 C -
1 170031 170032 C -
文件 2:
1 170023 170024 A
1 170024 170025 T
1 170025 170026 G
1 170026 170027 A
1 170027 170028 G
1 170028 170029 T
1 170029 170030 A
1 170030 170031 G
1 170031 170032 C
我想将文件 2 的第 4 列(仅字母列)添加到文件 1。通常,使用 pr
或 paste
会很容易,但问题是两个文件中的第 1-3 列不同。换句话说,文件的行数不同,文件 2 的行数总是比文件 1 多(特别是,文件 1 中第 2 列和第 3 列中的所有数字也出现在文件 2 中,但 vice相反)。我也知道如何在 R 中执行此操作,但文件太大而无法在 R 中轻松处理,我将需要为十几个文件完成任务。所以我想,bash 或任何命令行软件将是解决此问题的最有效方法。
当且仅当文件 2 中的第 1-3 列与文件 1 中的第 1-3 列完全匹配时,我真正想要做的是添加文件 2 中第 4 列的字母。因此,文件 1 的第 4 列和第 5 列中出现什么符号并不重要。根据上面文件 1 和文件 2 的示例,所需的输出将是:
输出:
1 170023 170024 A - A
1 170024 170025 T - T
1 170026 170027 A - A
1 170028 170029 G - T
1 170029 170030 C - A
1 170031 170032 C - C
如果有人能帮助我,我将非常高兴。非常感谢您!
我可以考虑并提供一个使用 join
和 awk
的简单解决方案。用 awk
可能不是解决它的最有效方法(可能会为此遭到专家的抨击 :)),但我能够解决这个问题。
解法-1:-
您需要做的就是首先使用 join
而不指定任何特定的列来加入。它会根据常见的重复列(在本例中为第 1 列)自动连接文件。然后在该输出上,我们可以让 awk
播放以打印符合您需要的那些行并格式化所需的列。
join file1 file2 | awk '{ if ((==) && (==)) printf("%s %s %s %s %s %s\n", , , , , , ) }'
为我生成的输出为
1 170023 170024 A - A
1 170024 170025 T - T
1 170026 170027 A - A
1 170028 170029 G - T
1 170029 170030 C - A
1 170031 170032 C - C
解法-2:-
仅使用普通 join
join -j 2 file1 file2 -o 1.1,1.2,1.3,1.4,1.5,2.4
也会产生与您预期相同的输出。
`join' writes to standard output a line for each pair of input lines that have identical join fields.
我引用 join
的 man
页面内容如下
`-j FIELD'
Equivalent to `-1 FIELD -2 FIELD'.
`-o FIELD-LIST'
Otherwise, construct each output line according to the format in
FIELD-LIST. Each element in FIELD-LIST is either the single
character `0' or has the form M.N where the file number, M, is `1'
or `2' and N is a positive field number.
因此该命令首先通过第 2 列连接 file1
和 file2
并打印所见输出中所需的列,由 (1.1
,1.2
表示,1.3
,1.4
,1.5
,2.4
) 应读作 file
.column
。为了更好地理解,我建议先查看不带 -o
选项的输出,以及我如何根据所见构建输出。
解法-3:-
使用plain'ol awk
,其实我自己在回答这个问题的时候也学到了一些。
awk 'FNR==NR{a[ FS FS ]=;next} (( FS FS ) in a) {print [=15=], a[ FS FS ]}' file2 file1
解释:-
FNR==NR{a[ FS FS ]=;next}
将处理file2
存储数组a
的条目,下标为 column1 space column2 space column3值为 column4.现在
file1
,我们需要通过执行(( FS FS ) in a) {print [=41=], a[ FS FS ]}
来匹配数组中file2
的那些行,这将给我所有这些行(我们需要file1
中 column4) 的值,其下标与file2
. 中的下标相同