在尝试优化一些与服务器相关的数据时,我和我的团队就linux命令的使用进行了讨论。请各位成员帮助我们更准确地理解这个概念。
在服务器上,我们有每分钟创建一次的日志文件,我们需要搜索带有特定标签的日志,例如:错误日志、超时日志、请求失败日志。在许多要求中,一个要求是提供有关这些标签计数的信息
简单的逻辑是awk特定字段(带分隔符)进行排序,并使用uniq-c命令计算此类实例的数量。
我可以看到两种执行方式:
cat fname | awk -F":" {'print $1'} | sort | uniq -c
和
awk -F":" {'print $1'} fname | sort | uniq -c
文件大小可以以GB为单位,因此哪个命令可能更有效。
有三种方法可以打开文件并让awk对其内容进行操作:
-
cat打开文件:
cat file | awk '...'
-
shell重定向打开文件:
awk '...' < file
-
awk打开文件
awk '...' file
这些选择中:
- 总是要避免,因为
cat
和管道正在使用资源,并且没有提供任何值,请谷歌UUOC(Useless UseOf Cat)了解详细信息
使用其他2种中的哪一种是有争议的:
- 优点是shell打开的是文件而不是工具,因此如果对所有工具都这样做,则可以依赖一致的错误处理
- 优点是该工具知道它正在操作的文件的名称(例如awk中的FILENAME),因此您可以在内部使用它
要查看差异,请考虑以下两个文件:
$ ls -l file1 file2
-rw-r--r-- 1 Ed None 4 Mar 30 09:55 file1
--w------- 1 Ed None 0 Mar 30 09:55 file2
$ cat file1
a
b
$ cat file2
cat: file2: Permission denied
看看当你试图使用两种打开它们的方法在两者的内容上运行awk时会发生什么:
$ awk '{print FILENAME, $0}' < file1
- a
- b
$ awk '{print FILENAME, $0}' file1
file1 a
file1 b
$ awk '{print FILENAME, $0}' < file2
-bash: file2: Permission denied
$ awk '{print FILENAME, $0}' file2
awk: fatal: cannot open file `file2' for reading (Permission denied)
请注意,当您使用重定向时,打开不可读文件file2的错误消息来自shell,因此看起来与我第一次尝试cat
时的错误消息完全相同,而让awk打开它时的错误信息来自awk,与shell消息不同,在不同的awk中也会有所不同。
请注意,当使用awk打开文件时,FILENAME填充有正在操作的文件的名称,但当使用重定向打开文件时则设置为-
。
我个人认为"3"(填充的FILENAME)的好处远远超过了"2"(文件打开错误的一致错误处理)的好处,所以我总是使用:
awk '...' file
对于你的特定问题,你会使用:
awk -F':' '{cnt[$1]++} END{for (i in cnt) print cnt[i], i}' fname
应该使用来避免毫无用处的cat
awk -F":" '{print $1}' fname | sort | uniq -c
但我的建议是,通过使用在awk
中查找唯一项目,甚至可以避免昂贵的sort
和uniq
命令
awk -F":" '!seen[$1]++' fname
这将打印独特的线条。
获取唯一计数:
awk -F":" '!count[$1]++{c++} END{print c}' fname
cat fname |
的速度稍微慢了一点,因为它必须将文件从磁盘复制到内核,然后复制到cat的缓冲区,然后再复制到一个管道,该管道再次到达内核,然后再到另一个进程。这不是很多,因为它应该只是一个线性的慢下来,内存中的复制也很快,但你可以总是(=不依赖于some_command
接受文件参数)通过替换来加快速度
cat one_file_name | some_command
带有
<one_file_name some_command
这将更快,因为它将直接将one_file_name设置为some_command
的stdin
。
<one_file_name
可以并且经常被放置在some_command
之后和下一个管道符号之前。我个人经常喜欢从它开始,因为它反映了cat(cat one_file_name
)从左到右的无用但有点常见的用法。