问题:
我有多个文本文件 (.fas),如下所示:
文件1.fas:
>species1
AICGICVIAGIAIYIAAICG
>species2
AICGIVVYICAGAYICAGCG
文件2.fas:
>species1
AIG
>species2
GCI
我感兴趣的是计算第二行中的字符数(当它们对齐时,一个文件中的所有物种都是相同的。
我目前的一张班轮:
for i in *.fas; do echo -n "$i," && grep -m 1 -A 1 '>' $i | tail -n 1 | wc -c; done;
这在一定程度上有效,但计算的数字比实际字符数高一个数字,因为它计算的是换行符。如何解决此问题,使其仅计算不包括换行符的字符数?
电流输出:
file1.fas,21
file2.fas,4
期望的输出:
file1.fas,20
file2.fas,3
答案1
| wc -l
打印行数。| wc -c
打印字符数,包括换行符。| wc -lc
打印两者(首先打印行数)。
所以你可以简单地减去它们:(写它而不是|wc -c
)
| wc -lc | awk '{print $2 - $1}'
如果只在一行上打印序列,则可以减去 1 而不是换行数。
或者您可以awk
仅使用,匹配整行并计算其字符数:
| awk '{match("[A-Z]*");print RLENGTH}'
RLENGTH
是匹配的长度(这里是整行)。在这里,我假设您仅使用大写字母,否则使用.
代替[A-Z]
。
在vim
(文本编辑器,因此它可能与您的脚本不兼容)上,直观地选择您的区域(一行或多行)并运行:
:'<,'>s/[A-Z]*//gn
您还可以使用以下命令删除换行符tr
(也适用于多行):
| tr -d '\n' | wc -c
顺便说一句,可能还有很多其他方法可以做到这一点。
答案2
用于find
查找 .fas 文件,find 命令会将它们推送到 awk 的命令行上,就像 awk 可以一次性处理的一样。因此 awk 调用的次数被最小化。
$ find . -maxdepth 1 -type f -name '*.fas' -exec \
awk -v OFS=, 'FNR==2{print FILENAME, length();nextfile}' {} +
输出:
./file1.fas,20
./file2.fas,3
答案3
使用以下 perl 单行命令,打印文件名和第二行的长度(以逗号分隔)。使用标志去除换行符-l
:
for i in *.fas; do perl -lne 'if ( $. == 2) { print join ",", $ARGV, length $_; last LINE; }' $i ; done
输入:
cat > file1.fas <<EOF
>species1
AICGICVIAGIAIYIAAICG
>species2
AICGIVVYICAGAYICAGCG
EOF
cat > file2.fas <<EOF
>species1
AIG
>species2
GCI
EOF
输出:
file1.fas,20
file2.fas,3
Perl 单行代码使用这些命令行标志:
-e
: 告诉 Perl 查找内联代码,而不是在文件中。
-n
:一次循环输入一行,$_
默认将其分配给。 :在内联执行代码之前
-l
剥离输入行分隔符(默认在 *NIX 上),并在打印时附加它。"\n"
$ARGV
是当前输入文件的名称。
length $_
是当前行的长度,已选择该行作为输入行号 2 ( $. == 2
)。
last LINE
使代码在打印行长度后跳到最后一个输入行,以提高速度。
也可以看看: