如何以最快的方式读取文件中的每 N 个字符?

如何以最快的方式读取文件中的每 N 个字符?

我已经知道在 bash 中每隔 N 个字符读取一个文件的几种方法:

LC_ALL=C
while read -n100 character; do
    echo "$character"
done < <(cat "$@" | tr -d '\n')
    echo "$character

但是,虽然这有效,但我希望知道更快的方法来做到这一点,无论是在 Bash 中,还是使用 posix/unix 工具。

还有其他方法可以更快地做到这一点吗?

答案1

复制AdminBee 的结果使用稍微简单的代码。

输入数据与他们的相同:

12345678901234
567890123
4567890123456789012
34567890123

从 10 开始,每 10 个字符:

$ fold -w 1 file | awk 'NR % 10 == 0'
0
0
0
0
0

相同,但从 1 开始:

$ fold -w 1 file | awk 'NR % 10 == 1'
1
1
1
1
1
1

相同,但从 2 开始:

$ fold -w 1 file | awk 'NR % 10 == 2'
2
2
2
2
2
2

就性能而言,这与 AdminBee 的awk解决方案相当,但在大输入上速度稍快(“大输入”==上述测试数据重复多次)。

fold -w 1输入中的每个字符生成一行,并丢弃换行符。使用的两个命令都是标准 POSIX 实用程序。

答案2

尝试这个解决方案,由于使用了“空字段分隔符”扩展,awk该解决方案适用于许多但并非所有实现:awk

awk -F "" -v l=100 '{last=0; for (i=1;i<=NF;i++) {if ((i+carry)%l==0) {print $i; last=i}};\
                     if (last) {carry=NF-last} else {carry+=(NF-l)}}' inputfile.txt

这会将每个字符视为单个字段 ( -F "") 并仅打印那些字段编号模“跳过长度” l(在您的情况下为 100)为零的字段,同时考​​虑结转但忽略换行符。

请注意,由于它从 1 开始计数,因此第一个字符是不是读。您可以使用

awk -F "" -v l=10 -v ofs=1 '{last=0; for (i=1;i<=NF;i++) {if ((i+carry)%l==ofs) {print $i; last=i}};\
                             if (last) {carry=NF-last+ofs} else {carry+=(NF-l)}}' inputfile.txt

通过 调整偏移量ofs

测试用例

在 Linux 系统上使用gawkmawk和进行了测试。nawk

  • 输入文件
    12345678901234
    567890123
    4567890123456789012
    34567890123
    
  • 输出“每 10 个,从第 10 个字符开始”
    $ awk -F "" -v l=10 '{last=0; for (i=1;i<=NF;i++) {if ((i+carry)%l==0) {print $i; last=i}}; if (last) {carry=NF-last} else {carry+=(NF-l)}}' testfile.txt 
    0
    0
    0
    0
    0
    
  • 输出“每 10 个,从第一个字符开始”
    $ awk -F "" -v l=10 -v ofs=1 '{last=0; for (i=1;i<=NF;i++) {if ((i+carry)%l==ofs) {print $i; last=i}}; if (last) {carry=NF-last+ofs} else {carry+=(NF-l)}}' testfile.txt 
    1
    1
    1
    1
    1
    1
    

相关内容