我已经知道在 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 系统上使用gawk
、mawk
和进行了测试。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