我对grep
/感到困惑egrep
。我认为这些工具与单行相匹配?在某些情况下我听到过“合乎逻辑”的台词。
grep
/egrep
总是一次处理一行直到新行字符是否正确?大多数工具实际上并不一次从文件中读取一行,而是使用内存中的缓冲区来存储行块。这些工具一次对该缓冲区中的数据操作一行。
注意:\n
“行”是指在grep
's 的情况下,或调用“工具”时被表示为“分隔符”的任何字符分隔。
下面用一个例子来说明这种效果。
创建一个包含 100,000 行的文件。该文件名为 afile100k。
$ for i in $(seq 100000);do echo "file$i" >> afile100k; done
Run Code Online (Sandbox Code Playgroud)
我们可以利用strace
正在运行的进程中的峰值,在本例中是grep
命令。
$ strace -s 2000 -o log100k grep 5 afile100k
Run Code Online (Sandbox Code Playgroud)
这会将输出记录到strace
文件中,每行输出最多 2000 个字符log100k
。我们要跟踪的命令是grep 5 afile100k
.
以下是日志的一些关键输出:
ioctl(3, SNDCTL_TMR_TIMEBASE 或 SNDRV_TIMER_IOCTL_NEXT_DEVICE 或 TCGETS, 0x7fff8bf73b20) = -1 ENOTTY(设备的 ioctl 不合适)
读取(3,“文件1\n文件2\n文件3\n文件4\n文件5\n文件6\n文件7\n文件8\n文件9\n文件10\n文件11\n文件12\n文件13\n文件14\n文件15\n文件16\n文件17\n文件18\n文件19\n文件20\n文件21\n文件22\n文件23 \n文件24\n文件25\n文件26\n文件27\n文件28\n文件29\n文件30\n文件31\n文件32\n文件33\n文件34\n文件35\n文件36\n文件37\n文件38\n文件39\n文件40\n文件41\n文件42\n文件43\n文件44\n文件45\n文件46\n文件47\n文件4 8 \n文件49\n文件50\n文件51\n文件52\n文件53\n文件54\n文件55\n文件56\n文件57\n文件58\n文件59\n文件60\n文件61\n文件62\n文件63\n文件64\n文件65\n文件66\n文件67\n文件68\n文件69\n文件70\n文件71\n文件72\n文件7 3 \n文件74\n文件75\n文件76\n文件77\n文件78\n文件79\n文件80\n文件81\n文件82\n文件83\n文件84\n文件85\n文件86\n文件87\n文件88\n文件89\n文件90\n文件91\n文件92\n文件93\n文件94\n文件95\n文件96\n文件97\n文件9 8 \n文件99\n文件100\n文件101\n文件102\n文件103\n文件104\n文件105\n文件106\n文件107\n文件108\n文件109\n文件110\n文件111\n文件112\n文件113\n文件114\n文件115\n文件116\n文件117\n文件118\n文件11 9\n文件 120\n文件 121\n文件 122\n文件 123 \n文件124\n文件125\n文件126\n文件127\n文件128\n文件129\n文件130\n文件131\n文件132\n文件133\n文件134\n文件135\n文件136\n文件137\n文件138\n文件139\n文件140\n文件141\n文件142\n文件143\n文件1 44\n文件145\n文件146\n文件147\n文件148 \n文件149\n文件150\n文件151\n文件152\n文件153\n文件154\n文件155\n文件156\n文件157\n文件158\n文件159\n文件160\n文件161\n文件162\n文件163\n文件164\n文件165\n文件166\n文件167\n文件168\n文件1 69\n文件170\n文件171\n文件172\n文件173 \n文件174\n文件175\n文件176\n文件177\n文件178\n文件179\n文件180\n文件181\n文件182\n文件183\n文件184\n文件185\n文件186\n文件187\n文件188\n文件189\n文件190\n文件191\n文件192\n文件193\n文件1 94\n文件195\n文件196\n文件197\n文件198 \n文件199\n文件200\n文件201\n文件202\n文件203\n文件204\n文件205\n文件206\n文件207\n文件208\n文件209\n文件210\n文件211\n文件212\n文件213\n文件214\n文件215\n文件216\n文件217\n文件218\n文件2 19\n文件220\n文件221\n文件222\n文件223 \n文件224\n文件225\n文件226\n文件227\n文件228\n文件229\n文件230\n文件231\n文件232\n文件233\n文件234\n文件235\n文件236\n文件237\n文件238\n文件239\n文件240\n文件241\n文件242\n文件243\n文件2 44\n文件245\n文件246\n文件247\n文件248 \n文件249\n文件250\n文件251\n文件252\n文件253\n文件254\n文件255\n文件256\n文件257\n文件258\n文件259\n文件260\n文件261\n文件262\n文件263\n文件"..., 32768) = 32768
Run Code Online (Sandbox Code Playgroud)lseek(3, 32768, SEEK_HOLE) = 988895 lseek(3, 32768, SEEK_SET) = 32768
注意grep
一次读取 32k (32768)。注意:我尝试将日志稍微分解一下,以便在 SE 上更容易阅读。
现在它开始写出结果:
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 5), ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fcafcfff000
write(1, "file5\n", 6) = 6
write(1, "file15\n", 7) = 7
write(1, "file25\n", 7) = 7
write(1, "file35\n", 7) = 7
write(1, "file45\n", 7) = 7
write(1, "file50\n", 7) = 7
Run Code Online (Sandbox Code Playgroud)
耗尽该缓冲区的内容后,它将重新从文件中读取下一个 32k (32768) 块。
write(1, "file3759\n", 9) = 9
read(3, "\nfile3765\nfile3766\nfile3767\nfile3768\nfile3769\nfile3770\nfile3771\nfile3772\nfile3773....\nfile3986\nf"..., 32768) = 32768
Run Code Online (Sandbox Code Playgroud)
接下来是更多的写入:
write(1, "file3765\n", 9) = 9
write(1, "file3775\n", 9) = 9
Run Code Online (Sandbox Code Playgroud)
Grep 继续执行此操作,直到完全耗尽文件的内容,此时结束。
write(1, "file99995\n", 10) = 10
read(3, "", 24576) = 0
close(3) = 0
close(1) = 0
munmap(0x7fcafcfff000, 4096) = 0
close(2) = 0
exit_group(0) = ?
+++ exited with 0 +++
Run Code Online (Sandbox Code Playgroud)