我正在开发一个项目,需要将多个文件中的特定数据行整理到一个新的文本文件中。例如,假设我有 3 个文件,每个文件都包含一个值矩阵:
文本文件1
Obs. TGCP_WM23 STT_WM189 MPO_WM496 PTP_WM724
TGCP_WM23 0.000000 0.174510 0.153292 0.177030
STT_WM189 0.174510 0.000000 0.077663 0.203359
MPO_WM496 0.153292 0.077663 0.000000 0.183706
PTP_WM724 0.177030 0.203359 0.183706 0.000000
文本文件2
Obs. TGCP_WM15 STT_WM187 MPO_WM485 PTP_WM725
TGCP_WM15 0.000000 0.157164 0.145516 0.168991
STT_WM187 0.157164 0.000000 0.051973 0.187443
MPO_WM485 0.145516 0.051973 0.000000 0.171824
PTP_WM725 0.168991 0.187443 0.171824 0.000000
文本文件3
Obs. TGCP_WM1 STT_WM184 MPO_WM489 PTP_WM721
TGCP_WM1 0.000000 0.166831 0.161654 0.192732
STT_WM184 0.166831 0.000000 0.059373 0.202718
MPO_WM489 0.161654 0.059373 0.000000 0.185286
PTP_WM721 0.192732 0.202718 0.185286 0.000000
我想自动读取这 3 个文件并将每个文件的第二行打印到一个新文本文件的连续行中,这样新文本文件包含:
新建文本文件
TGCP_WM23 0.000000 0.174510 0.153292 0.177030
TGCP_WM15 0.000000 0.157164 0.145516 0.168991
TGCP_WM1 0.000000 0.166831 0.161654 0.192732
有没有一种相对简单的方法可以使用 Mac 上的终端来执行类似的操作?目前,我正在查看 2,200 个文件,我需要从中提取数据并格式化数据,以便可以运行一些下游分析。我希望避免手动打开所有这些文件,复制文本并粘贴到新文件中,其中值以更有用的方式格式化。
编辑:我正在处理的所有文件都是从名为 Genodive 的程序输出的文本文件。一半的文件是 Fst 矩阵文件,类似于上面显示的示例;其他 1,100 个文件是遗传多样性输出文件,其内容看起来像......
___________________________________________________________________
GenoDive 3.01, 2019-12-12 23:28:01 +0000
Genetic Diversity: Nei 1987.
File: TrkNbr_1083n1282_L1n2_PrelimPops_02SubSampPops_Rep001.txt
8 of 8 individuals included, 6843 of 6843 loci included
– Summary of indices of genetic diversity
Statistic Value Std.Dev. c.i.2.5% c.i.97.5% Description
Num 1.418 0.006 1.405 1.428 Number of alleles
Eff_num 1.086 0.002 1.082 1.088 Effective number of alleles
Ho 0.092 0.002 0.089 0.096 Observed Heterozygosity
Hs 0.098 0.002 0.094 0.101 Heterozygosity Within Populations
Ht 0.114 0.002 0.110 0.117 Total Heterozygosity
H't 0.122 0.002 0.117 0.125 Corrected total Heterozygosity
Gis 0.055 0.013 0.030 0.079 Inbreeding coefficient
Standard deviations of F-statistics were obtained through jackknifing over loci.
95% confidence intervals of F-statistics were obtained through bootstrapping over loci.
– Indices of genetic diversity per population
Population Num Eff_num Ho Hs Gis
TGCP_WM3 1.261 1.183 0.142 0.141 -0.003
STT_WM186 1.186 1.132 0.088 0.108 0.183
MPO_WM483 1.194 1.136 0.097 0.109 0.110
PTP_WM732 1.095 1.068 0.056 0.051 -0.097
___________________________________________________________________
我不需要同时处理 Fst 文件和遗传多样性文件,我想从每种类型的文件中提取不同的数据。
两种文件类型的命名约定如下:
第一个文件被命名为
TrkNbr_1083n1282_L1n2_PrelimPops_02SubSampPops_Rep001_FstRslts
遗传多样性文件命名为
TrkNbr_1083n1282_L1n2_PrelimPops_02SubSampPops_Rep001_GenDivRslts
文件名的区别部分是“##SubSampPops_Rep###”部分。有 1,100 个“FstRslts”文件,这 1,100 个文件被细分为 11 组,每组 100 个文件...
02SubSampPops_Rep001
02SubSampPops_Rep002
02SubSampPops_Rep003
.
.
.
02SubSampPops_Rep100
04SubSampPops_Rep001
04SubSampPops_Rep002
04SubSampPops_Rep003
.
.
.
04SubSampPops_Rep100
同样,有 1,100 个“GenDivRslts”文件以相同的方式组织。
答案1
首先我们在命令行上定义一些有用的 shell 变量:
$ d='[0-9]'
$ pre='TrkNbr_1083n1282_L1n2_PrelimPops'
$ main="$d${d}SubSampPops_Rep$d$d$d"
$ post='GenDivRslts'
$ filename="${pre}_${main}_${post}"
使用 GNU awk
:
$ find . -type f -name "$filename" |
sort -t_ -nk5.1,5.2 -nk6.4,6.6 |
xargs -r awk 'FNR==2{print;nextfile}' \
> new_text_file;
使用 GNU sed
:
$ find . -type f -name "$filename" |
sort -t_ -nk5.1,5.2 -nk6.4,6.6 |
xargs -r sed -se '2!d' \
> new_text_file;
和perl
:
$ find . -type f -name "$filename" |
sort -t_ -nk5.1,5.2 -nk6.4,6.6 |
xargs -r perl -ne 'print,close ARGV if $. == 2' \
> new_text_file;
和head/tail
:
$ find . -type f -name "$filename" |
sort -t_ -nk5.1,5.2 -nk6.4,6.6 |
xargs -r \
sh -c '
for f
do
head -n 2 "$f" | tail -n 1
done
' x > new_text_file;
答案2
为什么不简单地
awk 'FNR == 2' *FstRslts > NewFile
?如果命令行变得太长,请尝试按输入文件的细分对输入文件进行分组,或使用xargs
分割行。
答案3
zsh
版本(Mac 终端中的默认 shell):
for file in $(find . -type f -iname "*.txt"); cat "$file" | head -2 | tail -1 >> output.txt
这假设所有输入文本文件都位于同一目录中,并且处理文件的顺序并不重要。
bash
版本:
for file in $(find . -type f -iname "*.txt"); do cat $file | head -2 | tail -1; done >> output.txt
编辑1:echo
没有必要 遵循纳西尔和 Steeldriver 的建议进行命令替换。以下是 awk 版本,
for file in $(find . -type f -iname "*.txt"); awk 'NR==2' $file >> output.txt
而且,如果文件没有扩展名,txt
则可以使用所有文件中通用的任何模式。假设所有文件的File
名称中都有,awk
版本可以是
for file in $(find . -type f -iname "*File*"); awk 'NR==2' $file >> output.txt
编辑2:
根据您所提到的,您的FstRslts
和GenDivRslts
是文件组的唯一标识符。因此,您可以"*FstRslts"
为您的FstRslts
文件使用,而不是"*.txt"
.同样适用于GenDivRslts
笔记
我正在接受@steeldrivers的建议和课程,并添加以下内容作为答案之一(更惯用):
find . -type f -iname "*FstRslts" -exec awk 'NR==2' {} \; > output.txt
编辑3
find .
- 从当前工作目录开始搜索
type -f
- 搜索文件类型
-iname "*FstRslts"
- 搜索与模式匹配的文件名时忽略大小写
-exec
- 执行以下命令
awk 'NR==2'
- 提取由于先前命令而找到的每个文件的第二行(匹配模式)
{} \;
- 文件(匹配模式)命令终止的占位符
> output.txt
- 将结果重定向到文件名“output.txt”