我使用以下命令创建 22 个文件:
user@host$ awk '{ print $1, $3, $4, $5 }' chr22.gen > snps22
user@host$ awk '{ print $1, $3, $4, $5 }' chr21.gen > snps21
...
user@host$ awk '{ print $1, $3, $4, $5 }' chr1.gen > snps1
输出文件如下所示:
user@host$ head snps21
rs885550 9887804 C T
rs169757 9928594 A C
rs210498 9928860 C T
rs210499 9929079 C A
rs303304 9941889 A G
...
我想做的是修改这些输出文件(snps22
、snps21
、snps20
...),例如snps21
如下所示:
user@host$ head snps21
rs885550 21:9887804:C:T
rs169757 21:9928594:A:C
rs210498 21:9928860:C:T
rs210499 21:9929079:C:A
rs303304 21:9941889:A:G
...
因此需要用chr21.gen
冒号将输入文件名称中的数字(即 21)连接到输出文件的第二列,然后用冒号连接第二、第三和第四列。
答案1
假设您的文件完全按照您所显示的方式调用,即字符串snps
后跟染色体名称,那么您可以使用
for name in snps*; do
awk 'FNR == 1 { chr = substr(FILENAME, 5) }
{ printf("%s %s:%s:%s:%s\n", $1, chr, $2, $3, $4) }' "$name" >"$name.new"
done
这将通过以下方式从文件名中提取染色体名称substr()
(染色体名称是文件名中从第 5 个字符开始的所有字符)。仅当读取文件的第一行 ( FNR == 1
) 时才会执行此操作。然后,代码以所需的格式输出当前行printf()
,并包含染色体名称。
然后将数据写入带有.new
文件名后缀的文件中。
awk
可以通过选择在哪里写入输出来消除 shell 循环:
awk 'FNR == 1 { chr = substr(FILENAME, 5); name = FILENAME ".new" }
{ printf("%s %s:%s:%s:%s\n", $1, chr, $2, $3, $4) >name }' snps*
您想将所有输出收集在一个文件中吗?这样就足够了
awk 'FNR == 1 { chr = substr(FILENAME, 5) }
{ printf("%s %s:%s:%s:%s\n", $1, chr, $2, $3, $4) }' snps* >all_snps
您还可以将修改后的变体应用于.gen
您拥有的原始文件:
awk 'FNR == 1 { chr = substr(FILENAME, 4); sub("\.gen$", "", chr)
name = "snps" chr }
{ printf("%s %s:%s:%s:%s\n", $1, chr, $3, $4, $5) >name }' chr*.gen
或者,对于单个输出文件,
awk 'FNR == 1 { chr = substr(FILENAME, 4); sub("\.gen$", "", chr) }
{ printf("%s %s:%s:%s:%s\n", $1, chr, $3, $4, $5) }' chr*.gen >all_snps
这只是从数据中选择稍微不同的列,并且必须提取文件名的另一部分来查找染色体的名称的问题。
答案2
使用 bash (以及 sed 和 tr)快速尝试:
for i in snps*
do
n=$(echo $i |tr -d 'a-zA-Z')
sed -i -e "s/ / $n:/" -e 's/ \([A-Z]\)/:\1/g' $i
done
这只是循环遍历以 snps2 开头的文件集,对于每个文件,它从名称中删除所有字母字符以获得数字部分,然后使用 sed (a) 将第一个空格替换为空格,即文件的数字部分文件名和冒号,(b) 将大写字母后面的每个空格替换为冒号。我很确定使用 awk 也可以同样好地完成。