作者都是各自领域经过审查的专家,并撰写他们有经验的主题. 我们所有的内容都经过同行评审,并由同一领域的Toptal专家验证.
伊利亚·萨诺西安的头像

Ilya Sanosian

伊利亚是一名IT顾问, web architect, 拥有12年以上团队建设和领导经验的经理.

Previously At

HUFFPOST
Share

可以说,日志是最被低估和未充分利用的工具之一 自由PHP开发人员’s disposal. 尽管日志可以提供丰富的信息,但将日志作为工具的情况并不少见 last 当试图解决问题时,放置开发人员的视线.

事实上,PHP日志文件在很多情况下应该是 first 当问题发生时寻找线索的地方. Often, 它们所包含的信息可以大大减少你揪着头发试图追踪一只粗糙的虫子所花费的时间.

但也许更重要的是, 再加上一点创造力和远见, 可以利用日志文件作为使用信息和分析的有价值的来源. 创造性地使用日志文件可以帮助回答以下问题:访问我的站点最常用的浏览器是什么? 服务器的平均响应时间是多少? 请求到站点根的百分比是多少? 自从我们部署了最新的更新以来,使用情况发生了怎样的变化? And much, much more.

PHP log files

本文提供了一些有关的技巧 如何配置日志文件, as well as 如何处理它们所包含的信息,以便最大限度地发挥它们所提供的效益.

尽管本文主要关注PHP开发人员的日志记录技术, 这里提供的许多信息与技术无关,也与其他语言和技术栈相关.

Note: 本文假定您对Unix shell有基本的了解. 对于那些缺乏这方面知识的人 Appendix 介绍了在Unix系统上访问和读取日志文件所需的一些命令.

我们的PHP日志文件示例项目

作为本文讨论目的的一个示例项目,我们将采用 Symfony Standard 作为一个工作项目,我们将把它安装在Debian 7 Wheezy上 rsyslogd, nginx, and PHP-FPM.

Composer - create-project symfony/framework-standard-edition my "2.6.*"

这很快就为我们提供了一个具有漂亮UI的工作测试项目.

配置日志文件的提示

这里有一些关于如何配置日志文件以帮助最大化其价值的指针.

错误日志配置

Error logs represent the most basic form of logging; i.e.,在出现问题时捕获额外的信息和细节. 因此,在理想情况下,您希望没有错误,并且错误日志为空. 但当问题发生时(这是不可避免的), 您的错误日志应该是您的 debugging trail.

错误日志通常很容易配置.

For one thing, 所有错误和崩溃消息都可以以与呈现给用户的格式完全相同的格式记录在错误日志中. 通过一些简单的配置, 最终用户将永远不需要在您的站点上看到那些丑陋的错误痕迹, 虽然开发人员仍然能够监视系统并查看这些错误消息的所有细节. 下面是如何在PHP中设置这种日志记录:

log_errors = On
error_reporting = E_ALL
Error_log = /path/to/my/error/log

另外两行很重要,应该包含在活动站点的日志文件中, 避免向用户呈现严重程度的错误细节, are:

display_errors = Off
display_startup_errors =关闭

System Log (syslog) Confguration

的许多一般兼容的实现 syslog Daemon在开源世界中包括:

  • syslogd and sysklogd -最常见于BSD系列系统, CentOS, Mac OS X, and others
  • syslog-ng – default for modern Gentoo and SuSE builds
  • rsyslogd – widely used on the Debian and Fedora 操作系统系列

(注意:在本文中,我们将使用 rsyslogd for our examples.)

基本的syslog配置通常足以在系统范围的日志文件中捕获日志消息 /var/log/syslog; might also be /var/log/messages or /var/log/system.log 取决于你使用的发行版).

系统日志提供了几个日志工具,其中八个(LOG_LOCAL0 through LOG_LOCAL7)为用户部署的项目保留. 例如,您可以在这里设置 LOG_LOCAL0 写入4个独立的日志文件,根据日志级别(i.e.,错误,警告,信息,调试):

# /etc/rsyslog.d/my.conf

local0.犯错/var/log/my/err.log
local0.警告/var/log/my/warning.log
local0.信息- / var / log /我/信息.log
local0.调试,/ var / log /我/调试.log

现在,每当您向 LOG_LOCAL0 设施,错误消息将转到 /var/log/my/err.log,警告信息将转到 /var/log/my/warning.log, and so on. Note, though, syslog守护进程根据“此级别及更高级别”的规则过滤每个文件的消息. So, in the example above, 所有错误消息将出现在所有四个配置文件中, 警告消息将出现在除错误日志之外的所有日志中, Info消息将出现在Info和debug日志中, 并且调试消息只会转到 debug.log.

One additional important note; The - 上述配置文件示例中的info和debug级别文件前面的符号表明,对这些文件的写入应该异步执行(因为这些操作是非阻塞的)。. 对于信息和调试日志来说,这通常是很好的(甚至在大多数情况下都是推荐的), 但是对错误日志(很可能还有警告日志)的写操作最好是同步的.

为了关闭不太重要的日志记录级别(例如.g.(在生产服务器上),您只需将相关消息重定向到 /dev/null (i.e., to nowhere):

local0.-/var/log/my/ Debug.log

一个有用的特定定制, 特别是支持一些PHP日志文件解析,我们将在本文后面讨论, 是否在日志消息中使用TAB作为分隔符. 这可以通过添加以下文件轻松完成 /etc/rsyslog.d:

# /etc/rsyslog.d/fixtab.conf

EscapeControlCharactersOnReceive美元

And finally, 不要忘记在您做了任何配置更改后重新启动syslog守护进程,以便它们生效:

rsyslog restart服务

服务器日志配置

与您可以写入的应用程序日志和错误日志不同, 服务器日志由相应的服务器守护进程(例如.g.、web服务器、数据库服务器等.) on each request. 您对这些日志的唯一“控制”是服务器允许您配置其日志记录功能. 虽然这些文件里有很多东西要筛选, 它们通常是清楚地了解服务器“底层”发生了什么的唯一方法.

让我们在nginx环境中使用MySQL存储后端部署Symfony Standard示例应用程序. 下面是我们将要使用的nginx主机配置:

server {
    server_name my.log-sandbox;
    root /var/www/my/web;

    location / {
        #尝试直接服务文件,退回到应用程序.php
        try_files $uri /app.php$is_args$args;
    }
    # DEV
    #该规则只适用于您的开发环境
    在生产环境中,不要包含这个,也不要部署app_dev.php or config.php
    位置~ ^/(app_dev|config)\.php(/|$) {
        fastcgi_pass unix: / var /运行/ php5-fpm.sock;
        fastcgi_split_path_info ^ (.+\.php)(/.*)$;
        包括fastcgi_params;
        $document_root$fastcgi_script_name;
        fastcgi_param HTTPS关闭;
    }
    # PROD
    location ~ ^/app\.php(/|$) {
        fastcgi_pass unix: / var /运行/ php5-fpm.sock;
        fastcgi_split_path_info ^ (.+\.php)(/.*)$;
        包括fastcgi_params;
        $document_root$fastcgi_script_name;
        fastcgi_param HTTPS关闭;
        #阻止包含前控制器的uri. This will 404:
        # http://domain.tld/app.php/some-path
        删除内部指令以允许这样的uri
        internal;
    }

    error_log /var/log/nginx/my_error.log;
    access_log /var/log/nginx/my_access.log;
}

关于上述最后两个指令: access_log 表示一般请求日志,而 error_log is for errors, and, 与应用程序错误日志一样, 设置额外的监控来提醒问题是值得的,这样您就可以快速做出反应.

Note: 这是一个故意过度简化的nginx配置文件,仅供示例使用. 它几乎不关注安全性和性能,不应该在任何“真实”环境中按原样使用.

这是我们得到的 /var/log/nginx/my_access.log after typing http://my.log-sandbox/app_dev.php/ 在浏览器中点击 Enter.

192.168.56.1 - - [26/Apr/2015:16:13:28 +0300] "GET /app_dev . exe。.php/ HTTP/1.1“200 6715”-“”Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML,像壁虎)Chrome/42.0.2311.90 Safari/537.36"
192.168.56.1 - - [26/Apr/2015:16:13:28 +0300] "GET /bundles/framework/css/body.css HTTP/1.1“200 6657”http://my.log-sandbox/app_dev.php/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML,像壁虎)Chrome/42.0.2311.90 Safari/537.36"
192.168.56.1 - - [26/Apr/2015:16:13:28 +0300] "GET /bundles/framework/css/structure.css HTTP/1.1“2001191”http://my.log-sandbox/app_dev.php/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML,像壁虎)Chrome/42.0.2311.90 Safari/537.36"
192.168.56.1 - - [26/Apr/2015:16:13:28 +0300] "GET /bundles/acmedemo/css/demo.css HTTP/1.1“2002204”http://my.log-sandbox/app_dev.php/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML,像壁虎)Chrome/42.0.2311.90 Safari/537.36"
192.168.56.1 - - [26/Apr/2015:16:13:28 +0300] "GET /bundles/acmedemo/images/welcome-quick-tour.gif HTTP/1.1" 200 4770 "http://my.log-sandbox/app_dev.php/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML,像壁虎)Chrome/42.0.2311.90 Safari/537.36"
192.168.56.1 - - [26/Apr/2015:16:13:28 +0300] "GET /bundles/acmedemo/images/welcome-demo.gif HTTP/1.1" 200 4053 "http://my.log-sandbox/app_dev.php/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML,像壁虎)Chrome/42.0.2311.90 Safari/537.36"
192.168.56.1 - - [26/Apr/2015:16:13:28 +0300] "GET /bundles/acmedemo/images/welcome-configure.gif HTTP/1.1" 200 3530 "http://my.log-sandbox/app_dev.php/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML,像壁虎)Chrome/42.0.2311.90 Safari/537.36"
192.168.56.1——[26/Apr/2015:16:13:28 +0300] "GET /favicon.ico HTTP/1.1" 200 6518 "http://my.log-sandbox/app_dev.php/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML,像壁虎)Chrome/42.0.2311.90 Safari/537.36"
192.168.56.1 - - [26/Apr/2015:16:13:30 +0300] "GET /app_dev . exe。.php/_wdt/e50d73 HTTP/1.1“200 13265”http://my.log-sandbox/app_dev.php/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML,像壁虎)Chrome/42.0.2311.90 Safari/537.36"

这表明,为了提供一个页面,浏览器实际上执行了9个HTTP调用. 然而,其中7个是对静态内容的请求,这是简单和轻量级的. 然而,它们仍然占用网络资源,这是可以通过使用各种优化的 sprites 还有缩小技术.

而这些优化将在另一篇文章中讨论, 这里相关的是,我们可以使用另一个单独记录请求到静态内容 location directive for them:

location ~ \.(jpg | jpeg | gif | png | ico css | | zip | tgz |广州| rar | bz2 |获取pdf | txt | tar | wav | bmp | rtf | js) $ {
    access_log /var/log/nginx/my_access-static.log;
}

Remember that nginx location 执行简单正则表达式匹配, 因此,您可以包含尽可能多的静态内容扩展,只要您希望在您的站点上分发.

解析此类日志与解析应用程序日志没有什么不同.

其他值得一提的日志

另外两个值得一提的PHP日志是调试日志和数据存储日志.

The Debug Log

关于nginx日志的另一个方便的事情是调试日志. 我们可以通过替换 error_log 下面的配置行(需要安装nginx调试模块):

error_log /var/log/nginx/my_error.log debug;

同样的设置适用于Apache或您使用的任何其他web服务器.

顺便提一下,调试日志是 not 与错误日志相关,即使它们在 error_log directive.

虽然调试日志确实可以是详细的(单个nginx请求, for example, 生成了127KB的日志数据!),但它仍然非常有用. 费力地浏览日志文件可能是麻烦和乏味的, 但它通常可以快速提供线索和信息,极大地帮助加快调试过程.

In particular, 调试日志确实可以帮助调试nginx配置, 尤其是最复杂的部分, like location matching and rewrite chains.

当然,绝不应该在生产环境中启用调试日志. 它们使用的空间量和存储的信息量也意味着服务器上的大量I/O负载, 哪些会显著降低整个系统的性能.

Data Storage Logs

另一种类型的服务器日志(对调试很有用)是数据存储日志. 在MySQL中,你可以通过添加这些行来打开它们:

[mysqld]
general_log = 1
General_log_file = /var/log/mysql/query.log

这些日志只是按时间顺序包含系统在处理数据库请求时运行的查询列表, 哪一个对各种调试和跟踪需求有帮助. However, 它们不应该在生产系统上保持启用状态, 因为它们会产生额外的不必要的I/O负载, 这会影响性能.

写入日志文件

PHP本身提供了打开、写入和关闭日志文件的函数(openlog(), syslog(), and closelog(), respectively).

There are also 众多日志库 用于PHP开发人员,例如 Monolog (popular among Symfony and Laravel users), 以及各种特定于框架的实现, 例如将日志记录功能合并到 CakePHP. 一般来说,像Monolog这样的库不仅封装 syslog() 调用,但也允许使用其他后端功能和工具.

下面是一个如何写入日志的简单示例:

Our call here to openlog:

  • 配置PHP在脚本的生命周期内为每个系统日志消息附加一个唯一标识符
  • 将其设置为延迟打开syslog连接,直到第一次 syslog() call has occurred
  • sets LOG_LOCAL0 作为默认的日志记录工具

下面是运行上述代码后日志文件的内容:

# cat /var/log/my/info.log
Mar 2 00:23:29 log-sandbox 54f39161a2e55:它工作!

最大化PHP日志文件的价值

现在我们都熟悉了理论和基础知识, 让我们看看在尽可能少地更改我们的样例Symfony Standard项目的情况下,我们可以从日志中获得多少信息.

首先,让我们创建脚本 src/log-begin.php (正确打开和配置我们的日志)和 src/log-end.php (记录有关成功完成的信息). 请注意,为了简单起见,我们只将所有消息写入信息日志.

# src/log-begin.php



# src/log-end.php

我们需要这些脚本 app.php:

对于开发环境,我们需要这些脚本 app_dev.php as well. 这样做的代码将与上面相同,只是我们将设置 MODE to DEV rather than PROD.

我们还想跟踪正在调用的控制器,所以让我们再添加一行 Acme \ DemoBundle \ EventListener \ ControllerListener,就在……的开头 ControllerListener: onKernelController () method:

syslog (LOG_INFO“控制器\ t” . get_class($event->getController()[0]));

注意,这些更改总共只增加了15行代码, 但可以共同产生丰富的信息.

分析日志文件中的数据

对于初学者,让我们看看每个页面加载需要多少HTTP请求.

下面是一个请求的日志信息,基于我们配置日志的方式:

Mar 3 12:04:20 log-sandbox 54f58724b1ccc:开始
Mar 3 12:04:20 log-sandbox 54f58724b1ccc: URI /app_dev.php/
Mar 3 12:04:20 log-sandbox 54f58724b1ccc: CLIENT.168.56.1    1b101cd
Mar 3 12:04:20 log-sandbox 54f58724b1ccc: MODE DEV
march 3 12:04:23 log-sandbox 54f58724b1ccc: CONTROLLER Acme\DemoBundle\ CONTROLLER \WelcomeController
3 . Mar 3 12:04:25 log-sandbox 54f58724b1ccc:调度时间.51
Mar 3 12:04:25 log-sandbox 54f58724b1ccc:结束
Mar 3 12:04:25 log-sandbox 54f5872967dea:开始
Mar 3 12:04:25 log-sandbox 54f5872967dea: URI /app_dev.php/_wdt/59b8b6
Mar 3 12:04:25 log-sandbox 54f5872967dea: CLIENT.168.56.1    1b101cd
Mar 3 12:04:25 log-sandbox 54f5872967dea: MODE DEV
3 12:04:28 log-sandbox 54f5872967dea: CONTROLLER Symfony\Bundle\WebProfilerBundle\ CONTROLLER \ProfilerController
Mar 3 12:04:29 log-sandbox 54f5872967dea:调度时间.17
Mar 3 12:04:29 log-sandbox 54f5872967dea:结束

因此,现在我们知道每个页面加载实际上是由两个HTTP请求提供的.

实际上这里有两点值得一提. First, 每次页面加载两个请求是用于在开发模式下使用Symfony(我在本文中一直这样做). 您可以通过搜索来识别开发模式调用 /app-dev.php/ URL chunks. 其次,假设每个页面加载都伴随着对Symfony应用程序的两个后续请求. 正如我们之前在nginx访问日志中看到的那样, 实际上有更多的HTTP调用, 其中一些用于静态内容.

OK, 现在让我们浏览一下演示站点(在日志文件中构建数据),看看我们还能从这些日志中学到什么.

自日志文件开始以来总共服务了多少个请求?

# grep -c BEGIN info.log
10

它们中是否有失败的(脚本是否在未到达结尾时关闭)?

# grep -c END info.log
10

我们看到的是 BEGIN and END 记录匹配,所以这告诉我们所有呼叫都成功了. (如果PHP脚本没有成功完成,它就不会执行 src/log-end.php script.)

请求到站点根的百分比是多少?

# ' grep -cE "\s/app_dev.php/$" info.log`
2

这告诉我们有2个页面加载站点根. 因为我们之前了解到(a)每次页面加载有2个请求,(b)总共有10个HTTP请求, 请求到站点根的百分比是40% (i.e., 2x2/10).

哪个控制器类负责为站点根提供请求?

# grep -E "\s/$|\s/app_dev.php/$" info.log | head -n1
Mar 3 12:04:20 log-sandbox 54f58724b1ccc: URI /app_dev.php/

# grep 54f58724b1ccc info.log | grep CONTROLLER
march 3 12:04:23 log-sandbox 54f58724b1ccc: CONTROLLER Acme\DemoBundle\ CONTROLLER \WelcomeController

在这里,我们使用请求的唯一ID来检查与该请求相关的所有日志消息. 因此,我们能够确定负责向站点根提供请求的控制器类是 Acme \ DemoBundle \ \ WelcomeController控制器.

哪些客户端ip地址为子网 192.168.0.0/16 访问过网站?

# grep CLIENT info.Log | cut -d":" -f4 | cut -f2 | sort | uniq
192.168.56.1

正如在这个简单的测试用例中所期望的那样,只有我的主机访问了站点. 这当然是一个非常简单的例子, 但是它所展示的能力(能够分析站点流量的来源)显然是非常强大和重要的.

我的网站有多少流量来自FireFox?

Having 1b101cd 作为我的Firefox User-Agent的哈希值,我可以这样回答这个问题:

# grep -c 1b101cd info.log
8
# grep -c CLIENT info.log
10

Answer: 80% (i.e., 8/10)

产生缓慢响应的请求的百分比是多少?

对于本示例而言, 我们将“慢”定义为需要超过5秒的时间来提供响应. Accordingly:

# grep“调度时间”信息.log | grep -cE "\s[0-9]{2,}\.|\s[5-9]\."
2

Answer: 20% (i.e., 2/10)

有人提供过GET参数吗?

# grep URI info.log | grep \?

No, Symfony标准只使用URL段, 这也告诉我们没有人试图入侵这个网站.

这些只是一些相对基本的示例,说明可以创造性地利用日志文件来产生有价值的使用信息,甚至是基本的分析.

其他需要记住的事情

Keeping Things Secure

另一个需要注意的是安全问题. 您可能认为记录请求是一个好主意,在大多数情况下确实如此. However, 在将任何潜在的敏感用户信息存储到日志中之前,一定要非常小心地删除它们,这一点非常重要.

对抗日志文件膨胀

因为日志文件是文本文件,您总是 append 信息,它们在不断增长. 因为这是一个众所周知的问题, 有一些相当标准的方法可以控制日志文件的增长.

The easiest is to rotate the logs. Rotating logs means:

  • 定期用新的空文件替换日志,以便进一步写入
  • 为历史记录存储旧文件
  • 删除已经“老化”到足以释放磁盘空间的文件
  • 确保当发生这些文件更改时,应用程序可以不间断地写入日志

最常见的解决方案是 logrotate,它预装在大多数*nix发行版中. 让我们看一个简单的配置文件来旋转我们的日志:

/var/log/my/debug.log
/var/log/my/info.log
/var/log/my/warning.log
/var/log/my/error.log
{
    rotate 7
    daily
    missingok
    notifempty
    delaycompress
    compress
    sharedscripts
    postrotate
        invoke-rc.d rsyslog rotate > /dev/null
    endscript
}

另一种更先进的方法是 rsyslogd 它将消息写入文件,根据当前日期和时间动态创建. 这仍然需要一个自定义的解决方案来删除旧文件, 但是可以让开发人员精确地管理每个日志文件的时间框架. For our example:

/var/log/my/error-%$NOW%-%$HOUR%.log"
$template DynaLocal0Info, "/var/log/my/info-%$NOW%-%$HOUR%.log"
$template DynaLocal0Warning, "/var/log/my/warning-%$NOW%-%$HOUR%.log"
/var/log/my/debug-%$NOW%-%$HOUR%.log"
local1.err      -?DynaLocal0Err
local1.info     -?DynaLocal0Info
local1.warning  -?DynaLocal0Warning
local1.debug    -?DynaLocal0Debug

This way, rsyslog 会每小时创建一个单独的日志文件吗, 并且不需要旋转它们并重新启动守护进程. 以下是如何删除超过5天的日志文件来实现此解决方案:

找到/var/log/my/ -mtime +5 -print0 | xargs -0 rm

Remote Logs

随着项目的增长,从日志中解析信息需要越来越多的资源. This not only means creating extra server load; it also means creating peak load on the CPU and disk drives at the times when you parse logs, 这会降低用户的服务器响应时间(或者在最坏的情况下甚至会使站点瘫痪)。.

要解决这个问题,可以考虑设置一个 集中式日志服务器. 您所需要的是另一个打开UDP端口514(默认)的盒子. To make rsyslogd 监听连接,在其配置文件中添加以下行:

$UDPServerRun 514

有了这些,设置客户端就很容易了:

*.*   @HOSTNAME:514

(where HOSTNAME 是远程日志服务器的主机名).

Conclusion

本文展示了一些创造性的方法,通过这些方法,日志文件可以提供比您以前想象的更有价值的信息, 重要的是要强调,我们只是触及了可能性的表面. 可以记录的内容的范围、范围和格式几乎是无限的. 这意味着——如果你想从日志中提取使用或分析数据——你只需要以一种易于后续解析和分析的方式记录它. 此外,该分析通常可以使用标准的Linux命令行工具执行,例如 grep, sed, or awk.

实际上,PHP日志文件是一个非常强大的工具,可以带来巨大的好处.

Resources

Code on GitHub: http://github.com/isanosyan/toptal-blog-logs-post-example


附录:在Unix Shell中读取和操作日志文件

下面简要介绍一些比较常用的*nix命令行工具,您需要熟悉这些工具来读取和操作日志文件.

  • cat 也许是最简单的一个. 它将整个文件打印到输出流. 例如,下面的命令将打印 logfile1 to the console:

    cat logfile1
    
  • > 字符允许用户重定向输出,例如重定向到另一个文件. 以写模式打开目标流(这意味着擦除目标内容). 的内容是这样替换的 tmpfile with contents of logfile1:

    cat logfile1 > tmpfile
    
  • >> 重定向输出并以追加模式打开目标流. 目标文件的当前内容将被保留,新的行将被添加到底部. This will append logfile1 contents to tmpfile:

    cat logfile1 >> tmpfile
    
  • grep 按某些模式过滤文件并只打印匹配的行. 命令将只打印 logfile1 containing Bingo message:

    grep Bingo logfile1
    
  • cut 打印单列的内容(按编号从1开始). 默认情况下,搜索制表符作为列之间的分隔符. 例如,如果文件中充满了格式的时间戳 YYYY-MM-DD HH:MM:SS,这将允许您只打印年份:

    cut -d"-" -f1 logfile1
    
  • head 只显示文件的第一行

  • tail 只显示文件的最后几行

  • sort 对输出中的行进行排序

  • uniq 过滤掉重复的行

  • wc 计数单词(或行) -l flag)

  • | (i.e.(“pipe”符号)将一个命令的输出作为下一个命令的输入. Pipe对于组合命令非常方便. 例如,下面是我们如何在一组时间戳中找到2014年的月份:

    grep - e "^2014" logfile1 | cut -d"-" -f2 | sort | uniq
    

这里,我们首先根据正则表达式“从2014年开始”匹配行,然后截断月份. 最后,我们使用of的组合 sort and uniq 只打印一次.

聘请Toptal这方面的专家.
Hire Now
伊利亚·萨诺西安的头像
Ilya Sanosian

Located in 牛津,英国

Member since September 19, 2013

About the author

伊利亚是一名IT顾问, web architect, 拥有12年以上团队建设和领导经验的经理.

Toptal作者都是各自领域经过审查的专家,并撰写他们有经验的主题. 我们所有的内容都经过同行评审,并由同一领域的Toptal专家验证.

Previously At

HUFFPOST

世界级的文章,每周发一次.

订阅意味着同意我们的 privacy policy

世界级的文章,每周发一次.

订阅意味着同意我们的 privacy policy

Toptal Developers

Join the Toptal® community.