我正在使用一个数据集,由我一直在编辑的 phylip 文件组成。 Phylip 格式是一种生物信息学格式,其中包含样本数量和序列长度作为标题,后跟每个样本及其序列。例如:
5 10
sample_1 gaatatccga
sample_2 gaatatccga
sample_3 gaatatcgca
sample_4 caatatccga
sample_5 gaataagcga
我的问题是,在修剪这些数据集时,标头中的样本数量不再准确(例如,在上面的示例中可能会说五个,但我已经修剪为只有三个样本)。我需要做的是将样本计数替换为新的、准确的样本计数,但我不知道如何在不丢失序列长度数字(例如 10)的情况下做到这一点。
我有 550 个文件,因此不能简单地手动执行此操作。我可以对 wc 进行 for 循环,但我再次需要保留该序列长度信息,并以某种方式将其与新的、准确的 wc 结合起来。
答案1
如果我正确理解您的要求,您可以使用以下awk
命令:
awk -v samples="$(($(grep -c . input)-1))" 'NR == 1 { $1=samples }1' input
samples
将设置为文件中的行数input
减一(因为您没有计算标题行)。
awk
然后将第一行的第一列更改为新的样本编号并打印所有内容。
$ cat input
5 10
sample_1 gaatatccga
sample_2 gaatatccga
sample_3 gaatatccga
$ awk -v samples="$(($(grep -c . input)-1))" 'NR == 1 { $1=samples }1' input
3 10
sample_1 gaatatccga
sample_2 gaatatccga
sample_3 gaatatccga
使用 GNU awk,您可以使用该-i
标志来修改适当的文件,但我更愿意制作第二组修改后的文件,以确保进行了正确的更改。
就像是:
for file in *.phy; do
awk -v samples="$(($(grep -c . "$file")-1))" 'NR == 1 { $1=samples }1' "$file" > "${file}.new"
done
答案2
另一种选择是使用ed
(当然!):
for f in input*
do
printf '1s/[[:digit:]][[:digit:]]*/%d\nw\nq' $(( $(wc -l < "$f") - 1 )) | ed -s "$f"
done
这会循环遍历文件(例如命名为input
-something)并将一个简单的 ed 脚本发送到ed
:
- 在线
1
,搜索并用s//
另一个数字替换 () 行开头的一个或多个数字 - 该替换数字是计算输入的行长度减一的结果 - 之后,
w
写出文件并 - 然后
q
退出ed
答案3
在 Vim 中,运行:
:execute '1s/^[0-9]\+/' . (line('$')-1) . '/'
(也感谢这个答案为我指明了正确的方向。)
您还可以在循环中执行此操作,例如使用shell 循环:bufdo
或仅使用 shellfor
循环。