Linux tail command outputs the last part of the files. There is an option to keep the file open for further entries. This makes it very useful to work with log files where we can check the logs in real-time when an event is happening.
1. Linux tail Command Syntax
The syntax of tail command is:
$ tail [OPTION]... [FILE]...
All the options and file names are optional.
2. What will tail do if no file is provided?
If you don’t provide the file name to tail, or specify it as a hyphen (-), the standard input is read.
3. Reading the last 10 lines of a File
If we don’t specify any option, the tail will read the last 10 lines of a file.
# tail error.log
2019-10-29 11:31:09.887840 [INFO] [16169] [APVH_recipes_Sulsphp73:]: locked pid file [/tmp/lshttpd/APVH_recipes_Suphp73.sock.pid].
2019-10-29 11:31:09.887968 [INFO] [16169] [APVH_recipes_Sulsphp73:] remove unix socket for detached process: /tmp/lshttpd/APVH_recipes_Suphp73.sock
2019-10-29 11:31:09.896280 [INFO] [16169] [APVH_recipes_Sulsphp73:] add child process pid: 27035, procinfo: 0x2c5e2b0
2019-10-29 11:31:09.896396 [INFO] [16169] [APVH_recipes_Sulsphp73:]: unlocked pid file [/tmp/lshttpd/APVH_recipes_Suphp73.sock.pid].
2019-10-29 11:31:17.182067 [INFO] [16169] [APVH_golangd_Sulsphp73:]: locked pid file [/tmp/lshttpd/APVH_golangd_Suphp73.sock.pid].
2019-10-29 11:31:17.182116 [INFO] [16169] [APVH_golangd_Sulsphp73:] remove unix socket for detached process: /tmp/lshttpd/APVH_golangd_Suphp73.sock
2019-10-29 11:31:17.182991 [INFO] [16169] [APVH_golangd_Sulsphp73:] add child process pid: 27067, procinfo: 0x447cff0
2019-10-29 11:31:17.183048 [INFO] [16169] [APVH_golangd_Sulsphp73:]: unlocked pid file [/tmp/lshttpd/APVH_golangd_Suphp73.sock.pid].
2019-10-29 11:31:20.641690 [INFO] [16169] [149.56.101.239:45604] [ACL] Access to context [/] is denied!
2019-10-29 11:31:27.245789 [INFO] [16169] [198.199.83.232:46876] [ACL] Access to context [/] is denied!
#
4. Linux tail Command Options
Short Option | Long Option | Description |
---|---|---|
-c | –bytes=K | output the last K bytes of the file. We can use “-c +K” to output bytes starting with the Kth of each file. |
-f | –follow[={name|descriptor}] | output appended data as the file grows. If we specify -F, it’s same as “–follow=name –retry” |
-n | –lines=K | output the last K lines, instead of the last 10; or use ‘-n +K’ to output starting with the Kth line. |
-q | –quiet, –silent | never output headers giving file names |
–retry | keep trying to open a file if it is inaccessible | |
-s | –sleep-interval=N | used with with -f to sleep for approximately N seconds (default 1.0) between iterations. |
-v | –verbose | always output headers giving file names |
–version | output version information and exit. |
- If the first character of K (the number of bytes or lines) is a ‘+’, print beginning with the Kth item from the start of each file, otherwise, print the last K items in the file.
- K may have a multiplier suffix: b 512, kB 1000, K 1024, MB 1000*1000, M 1024*1024, GB 1000*1000*1000, G 1024*1024*1024, and so on for T, P, E, Z, Y.
- With –follow (-f), tail defaults to following the file descriptor, which means that even if a tailed file is renamed, the tail will continue to track its end. This default behavior is not desirable when you really want to track the actual name of the file, not the file descriptor (e.g., log rotation).
- Use –follow=name in that case. That causes the tail to track the named file in a way that accommodates renaming, removal, and creation.
5. Linux tail Command Examples
Let’s look at some examples of tail command usage.
5.1) Limit the Number of Lines in tail Output
We can use -n or –lines option to limit the number of lines in the tail output.
# tail -n 5 error.log
# tail --lines=5 error.log
If we use + prefix with the option value, the output will be started from that line number in the file.
# wc -l error.log
27360 error.log
# tail -n +27358 error.log
2019-10-29 13:09:35.142604 [INFO] [16169] [APVH_javastr_Sulsphp73:] remove unix socket for detached process: /tmp/lshttpd/APVH_javastr_Suphp73.sock
2019-10-29 13:09:35.144320 [INFO] [16169] [APVH_javastr_Sulsphp73:] add child process pid: 18132, procinfo: 0x367c520
2019-10-29 13:09:35.144389 [INFO] [16169] [APVH_javastr_Sulsphp73:]: unlocked pid file [/tmp/lshttpd/APVH_javastr_Suphp73.sock.pid].
# tail --lines=+27358 error.log
2019-10-29 13:09:35.142604 [INFO] [16169] [APVH_javastr_Sulsphp73:] remove unix socket for detached process: /tmp/lshttpd/APVH_javastr_Suphp73.sock
2019-10-29 13:09:35.144320 [INFO] [16169] [APVH_javastr_Sulsphp73:] add child process pid: 18132, procinfo: 0x367c520
2019-10-29 13:09:35.144389 [INFO] [16169] [APVH_javastr_Sulsphp73:]: unlocked pid file [/tmp/lshttpd/APVH_javastr_Suphp73.sock.pid].
#
5.2) Limit the Number of Bytes in tail Output
We can use -c or –bytes option to output the specified bytes from the end of the file.
# tail -c 100 error.log
[16169] [APVH_android_Sulsphp73:]: unlocked pid file [/tmp/lshttpd/APVH_android_Suphp73.sock.pid].
# tail --bytes=100 error.log
[16169] [APVH_android_Sulsphp73:]: unlocked pid file [/tmp/lshttpd/APVH_android_Suphp73.sock.pid].
#
If we use + with the option value, the file data from that byte will be output to the console.
# ls -ltr error.log
-rw-r--r--. 1 nobody nobody 3475359 Oct 29 13:15 error.log
# tail -c +3475350 error.log
ock.pid].
#
5.3) Linux tail Command with Multiple Files
We can pass multiple file names and the output will have a header with the file name followed by the output.
# tail -n 2 error.log error.log.2019_10_27
==> error.log <==
2019-10-29 13:17:24.356633 [INFO] [16169] [APVH_golangd_Sulsphp73:] add child process pid: 19670, procinfo: 0x27af560
2019-10-29 13:17:24.356789 [INFO] [16169] [APVH_golangd_Sulsphp73:]: unlocked pid file [/tmp/lshttpd/APVH_golangd_Suphp73.sock.pid].
==> error.log.2019_10_27 <==
2019-10-27 20:26:31.050022 [INFO] [16169] [176.9.99.9:34084] [ACL] Access to context [/] is denied!
2019-10-27 20:26:31.216835 [INFO] [16169] [176.9.99.9:34118] [ACL] Access to context [/] is denied!
#
We can use -q option for silent output. It’s useful to merge the output from multiple files.
# tail -n 2 -q error.log error.log.2019_10_27
2019-10-29 13:18:44.095709 [INFO] [16169] [APVH_javastr_Sulsphp73:] add child process pid: 19947, procinfo: 0x4312b50
2019-10-29 13:18:44.095766 [INFO] [16169] [APVH_javastr_Sulsphp73:]: unlocked pid file [/tmp/lshttpd/APVH_javastr_Suphp73.sock.pid].
2019-10-27 20:26:31.050022 [INFO] [16169] [176.9.99.9:34084] [ACL] Access to context [/] is denied!
2019-10-27 20:26:31.216835 [INFO] [16169] [176.9.99.9:34118] [ACL] Access to context [/] is denied!
#
5.4) Watching a File for Changes
We can use -f option to watch the file for further changes. This is the most widely used option with the tail command. It’s useful to track logs in real-time and debug it.
[root@li1197-217 logs]# tail -f error.log
2019-10-29 13:22:31.719103 [INFO] [16169] [APVH_cultwpc_Sulsphp73:] add child process pid: 20640, procinfo: 0x384a9a0
2019-10-29 13:22:31.719172 [INFO] [16169] [APVH_cultwpc_Sulsphp73:]: unlocked pid file [/tmp/lshttpd/APVH_cultwpc_Suphp73.sock.pid].
2019-10-29 13:22:32.176946 [INFO] [16169] [APVH_android_Sulsphp73:]: locked pid file [/tmp/lshttpd/APVH_android_Suphp73.sock.pid].
2019-10-29 13:22:32.176979 [INFO] [16169] [APVH_android_Sulsphp73:] remove unix socket for detached process: /tmp/lshttpd/APVH_android_Suphp73.sock
2019-10-29 13:22:32.177901 [INFO] [16169] [APVH_android_Sulsphp73:] add child process pid: 20645, procinfo: 0x2df6830
2019-10-29 13:22:32.177955 [INFO] [16169] [APVH_android_Sulsphp73:]: unlocked pid file [/tmp/lshttpd/APVH_android_Suphp73.sock.pid].
2019-10-29 13:22:39.634710 [INFO] [16169] [APVH_javastr_Sulsphp73:]: locked pid file [/tmp/lshttpd/APVH_javastr_Suphp73.sock.pid].
2019-10-29 13:22:39.634755 [INFO] [16169] [APVH_javastr_Sulsphp73:] remove unix socket for detached process: /tmp/lshttpd/APVH_javastr_Suphp73.sock
2019-10-29 13:22:39.641576 [INFO] [16169] [APVH_javastr_Sulsphp73:] add child process pid: 20677, procinfo: 0x286e3b0
2019-10-29 13:22:39.641694 [INFO] [16169] [APVH_javastr_Sulsphp73:]: unlocked pid file [/tmp/lshttpd/APVH_javastr_Suphp73.sock.pid].
We can watch multiple files too with the -f option.
[root@li1197-217 logs]# tail -f error.log lsrestart.log
==> error.log <==
2019-10-29 13:22:31.719103 [INFO] [16169] [APVH_cultwpc_Sulsphp73:] add child process pid: 20640, procinfo: 0x384a9a0
2019-10-29 13:22:31.719172 [INFO] [16169] [APVH_cultwpc_Sulsphp73:]: unlocked pid file [/tmp/lshttpd/APVH_cultwpc_Suphp73.sock.pid].
2019-10-29 13:22:32.176946 [INFO] [16169] [APVH_android_Sulsphp73:]: locked pid file [/tmp/lshttpd/APVH_android_Suphp73.sock.pid].
2019-10-29 13:22:32.176979 [INFO] [16169] [APVH_android_Sulsphp73:] remove unix socket for detached process: /tmp/lshttpd/APVH_android_Suphp73.sock
2019-10-29 13:22:32.177901 [INFO] [16169] [APVH_android_Sulsphp73:] add child process pid: 20645, procinfo: 0x2df6830
2019-10-29 13:22:32.177955 [INFO] [16169] [APVH_android_Sulsphp73:]: unlocked pid file [/tmp/lshttpd/APVH_android_Suphp73.sock.pid].
2019-10-29 13:22:39.634710 [INFO] [16169] [APVH_javastr_Sulsphp73:]: locked pid file [/tmp/lshttpd/APVH_javastr_Suphp73.sock.pid].
2019-10-29 13:22:39.634755 [INFO] [16169] [APVH_javastr_Sulsphp73:] remove unix socket for detached process: /tmp/lshttpd/APVH_javastr_Suphp73.sock
2019-10-29 13:22:39.641576 [INFO] [16169] [APVH_javastr_Sulsphp73:] add child process pid: 20677, procinfo: 0x286e3b0
2019-10-29 13:22:39.641694 [INFO] [16169] [APVH_javastr_Sulsphp73:]: unlocked pid file [/tmp/lshttpd/APVH_javastr_Suphp73.sock.pid].
==> lsrestart.log <==
Thu Oct 10 17:45:33 UTC 2019
restart, LSWS running: 1
Wed Oct 23 08:53:16 UTC 2019
restart, LSWS running: 1
Wed Oct 23 09:03:02 UTC 2019
restart, LSWS running: 1
We can also specify the number of lines in the output with the -f option.
# tail -2f error.log
2019-10-29 13:28:46.086130 [INFO] [16169] [APVH_cultwpc_Sulsphp73:] add child process pid: 21976, procinfo: 0xd032210
2019-10-29 13:28:46.086193 [INFO] [16169] [APVH_cultwpc_Sulsphp73:]: unlocked pid file [/tmp/lshttpd/APVH_cultwpc_Suphp73.sock.pid].
5.5) Using the tail Command with pipe and grep
Sometimes we are interested in only specific messages in the tail output. We can use the tail command with pipe and grep to filter the specific messages in the output.
# tail -100f error.log | grep 'denied'
2019-10-29 13:21:49.170651 [INFO] [16169] [159.65.53.153:38448] [ACL] Access to context [/] is denied!
2019-10-29 13:22:00.991330 [INFO] [16169] [182.71.209.203:22089] [ACL] Access to context [/] is denied!
2019-10-29 13:25:47.188167 [INFO] [16169] [79.137.42.145:36674] [ACL] Access to context [/] is denied!
2019-10-29 13:25:52.668213 [INFO] [16169] [162.144.60.165:52886] [ACL] Access to context [/] is denied!
5.6) Using tail command to filter another command output
We can use the tail command with another command to filter the output lines. It’s useful when we are interested only in the few lines from a command output.
# ls -ltr | tail -n 3
-rw-r--r--. 1 nobody nobody 24406 Oct 23 09:08 error.log.2019_10_23.02
-rw-r--r--. 1 nobody nobody 10486279 Oct 27 20:26 error.log.2019_10_27
-rw-r--r--. 1 nobody nobody 3494794 Oct 29 13:29 error.log
#
# ls -ltr | tail -n +15
-rw-r--r--. 1 nobody nobody 10490954 Oct 21 09:42 error.log.2019_10_21
-rw-r--r--. 1 nobody nobody 10485856 Oct 22 07:44 error.log.2019_10_22
-rw-r--r--. 1 nobody nobody 10485809 Oct 22 14:16 error.log.2019_10_22.01
-rw-r--r--. 1 nobody nobody 5398751 Oct 23 08:29 error.log.2019_10_23
-rw-r--r--. 1 nobody nobody 61485 Oct 23 08:58 error.log.2019_10_23.01
-rw-r--r--. 1 root root 162 Oct 23 09:03 lsrestart.log
-rw-r--r--. 1 nobody nobody 24406 Oct 23 09:08 error.log.2019_10_23.02
-rw-r--r--. 1 nobody nobody 10486279 Oct 27 20:26 error.log.2019_10_27
-rw-r--r--. 1 nobody nobody 3499801 Oct 29 13:34 error.log
5.7) Printing tail version
We can use –version to print the tail command version.
# tail --version
tail (GNU coreutils) 8.22
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later .
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Written by Paul Rubin, David MacKenzie, Ian Lance Taylor,
and Jim Meyering.
#
5.8) tail command verbose output
If we use the verbose option, the output will have a header with the file name.
# tail -v -n 2 error.log
==> error.log <==
2019-10-29 13:39:30.769561 [INFO] [16169] [APVH_javastr_Sulsphp73:] add child process pid: 24454, procinfo: 0x405b840
2019-10-29 13:39:30.769618 [INFO] [16169] [APVH_javastr_Sulsphp73:]: unlocked pid file [/tmp/lshttpd/APVH_javastr_Suphp73.sock.pid].
#
6. Conclusion
Linux tail command is very useful to debug log messages in real-time. It's a great tool for developers to work with log files.
Reference: Wikipedia Page