The humble cat command in Linux hides impressive powers behind its mundane exterior. Developed over 40 years ago as part of the early Unix ecosystem, cat has retained its usefulness even today thanks to robust design and flexibility. As a full-stack developer well-versed in Linux, I often reach for cat to tackle numerous tasks from inspecting logs to analyzing code.
In this comprehensive 3500+ word guide, you will learn advanced yet practical uses of the cat command with a special focus on the line numbering powers unlocked via the -n option.
I will cover examples most relevant to software developers and coders, but sysadmins, data engineers and technical users will also find plenty of helpful techniques here. The aim is to provide actionable insights you can apply immediately rather than just conceptual theory.
So let‘s get started exploring the many manifestations of cat -n!
Popularity Among Developers
While intuitive graphical tools get a lot of attention these days, the good old cat command remains firmly ingrained in the workflows of most professional Linux users.
It consistently ranks among the top 15 most used commands across sysadmins, developers and power users. Beyond simplicity, flexibility is why it has retained such appeal.
In StackOverflow‘s 2020 survey, over 50% of professional developers reported using Linux. And the command line plays a huge role in Linux-based development. Whether it is analyzing build failures, inspecting test output or reviewing new code changes – tasks like these require sifting through log and text file output.
Here the cat command shines thanks to compact implementation and lightweight footprint. It adds no extra layers or complexity to text processing unlike some alternatives. Combine that with battle-tested stability across Linux/Unix distros and you have an indispensable tool.
Line Numbering Use Cases
Let‘s now examine some common use cases where cat‘s -n option brings real value:
1. Debugging Code
The most obvious use case is viewing code files with added line numbers. Languages like Python, Javascript, Java rely on line numbers to pinpoint issues.
For example, here is a sample Python exception trace:
File "script.py", line 8
print(misspelled_variable)
^
SyntaxError: name ‘misspelled_variable‘ is not defined
Debugging this without line numbers would prove tricky in a sizable script. With cat -n, you can quickly reveal the offending line:
5 def print_message():
6 message = "Hello world"
7
8 print(misspelled_variable)
-> 9 print(message)
The root cause jumps out thanks to the line number prefix.
2. Inspecting Stack Traces
Similarly, Java stack traces rely heavily on line numbers:
Exception in thread "main" java.lang.NullPointerException
at com.example.mypackage.Book.getTitle(Book.java:16)
at com.example.mypackage.Author.getBookTitles(Author.java:25)
at com.example.mypackage.Bootstrap.main(Bootstrap.java:7)
Pinpointing the root trigger out of multiple chained method calls is greatly aided by the line numbers present.
3. Reviewing Log Files
Server and application log files frequently embed line info to tag each event:
[20110802:15:36:30 +0100] "GET /index.php HTTP/1.1" 500 2034
"/home/user/bad_script.php(32):
include_once(/home/user/missing_file.php)"
Here the broken script being included is clearly identified via the line number – crucial debugging context that saves precious troubleshooting time.
4. Analyzing Test Output
Unit test and integration test frameworks include line numbers as part of failed assertions:
scrollbar_test.py:248: AssertionError
Expected: "Scroll Mode: overlay-auto",
Got: "Scroll Mode: disabled"
Rapidly hunting down the 248th line simplifies debugging compared to manually tracing execution flow across a large test suite.
As you can see, line numbers serve an indispensable role across many common tasks for developers. Let‘s now see how cat -n can fulfill these diverse needs.
Getting Started with Cat -n
On its own, the cat command simply outputs a file "as is" without any additions:
$ cat test.txt
Hello world
Greetings
Activate line numbering with the -n flag:
$ cat -n test.txt
1 Hello World
2 Greetings
Now let‘s try some more examples tailored to developer use cases.
Display Line Numbers for Code Files
Viewing code files is where cat -n truly earns its stripes thanks to the ubiquity of line numbers in code.
Let‘s try it on a sample Python script – test.py:
import math
def calc_area(radius):
area = math.pi * (radius ** 2)
print(f"Area = {area}")
calc_area(5)
print("Done")
Feed it through cat -n:
1 import math
2
3 def calc_area(radius):
4 area = math.pi * (radius ** 2)
5 print(f"Area = {area}")
6
7 calc_area(5)
8 print("Done")
Line numbers stand out clearly even for a small script. As code size and complexity increases, the visual mapping cat -n provides makes parsing complex logic much easier.
You can pass multiple files to get cumulative numbering across an entire codebase:
$ cat -n module1.py module2.py module3.py > all_code.txt
This concatenated, numbered view is invaluable for tracing variable scopes across files or assessing test coverage.
Inspect Stack Traces
Let‘s turn to parsing Java exceptions. Here is a sample stack trace triggerred from a Maven build:
[INFO] -------------------------------------------------------------
[ERROR] COMPILATION ERROR :
[INFO] -------------------------------------------------------------
[ERROR] /home/user/projects/helloapp/core/src/main/java/com/mycompany/hello/HelloPrinter.java:[3,20] cannot find symbol
symbol: class HellowWorld
location: class com.mycompany.hello.HelloPrinter
The key detail is the class not being found on line 3. But scrolling through Java package imports to spot line 3 is cumbersome.
Let‘s employ cat -n instead:
1 package com.mycompany.hello;
2
3 import HellowWorld; <- COMPILATION ERROR
4
5 public class HelloPrinter{
6
7 public static void main(String[] args){
8 HellowWorld hello = new HellowWorld();
9 hello.printHello();
10 }
11
12 }
The source of the issue jumps out without any scanning or scrolling needed thanks to the numbered view!
You can use this technique to inspect Java stack traces from builds as well as those printed during runtime.
Debugging Failures from External Processes
So far we viewed files generated internally by our own code. But what about output from external processes?
Take this sample Python stack trace:
Traceback (most recent call last):
File "/usr/lib/python3.8/site.py", line 797, in <module>
main()
File "/usr/lib/python3.8/site.py", line 779, in main
execsitecustomize()
File "/usr/lib/python3.8/site.py", line 671, in execsitecustomize
import sitecustomize
ModuleNotFoundError: No module named ‘sitecustomize‘
This appears to be triggerred from a Python virtual env creation process. Let‘s run it through cat -n:
1 Traceback (most recent call last):
2 File "/usr/lib/python3.8/site.py", line 797, in <module>
3 main()
4 File "/usr/lib/python3.8/site.py", line 779, in main
5 execsitecustomize()
6 File "/usr/lib/python3.8/site.py", line 671, in execsitecustomize
7 import sitecustomize
-> 8 ModuleNotFoundError: No module named ‘sitecustomize‘
The terminal output gets tagged with line numbers that pinpoint the failure origin!
This works for any textual output whether from build systems like Make, test runners or custom shell scripts.
Advanced Cat -n Invocation Examples
Now that we have covered basic usage for developer tasks, let‘s level up with some more advanced examples.
We will employ piping and redirection along with handy command line options to further extend cat‘s capabilities.
Redirect Only Line Number Output
When running cat -n on a large file, the bulk file content in the output can make it easy to miss the line numbers.
To extract only the numbering, we can filter the output by first redirecting it to a file:
$ cat -n test.txt > test_numbered.txt
This numbered file can then be piped to awk to extract just the line digits:
$ cat -n test.txt > test_numbered.txt
$ cat test_numbered.txt | awk ‘{print $1}‘
1
2
For additional clarity, the line numbers can be right padded to equal widths using printf:
$ cat test_numbered.txt | awk ‘{printf "%4s\n", $1}‘
1
2
This gives us just the numbered position markers against which we can visually map the file‘s actual contents.
Number Lines Across Codebases
Large projects often comprise multiple interconnected modules residing in separate files.
Here is a handy one-liner to get cumulative line numbering across an entire codebase:
$ cat -n $(find src -name ‘*.java‘) > all-lines.txt
This will recurse into the src directory for locating all .java files which get passed to cat -n before redirecting output to all-lines.txt.
The resultant file will have numbered lines spanning across all java packages and classes in sequence.
You can modify the find options to target other extensions like .py or .js based on project language.
Surface Hidden Characters
Beyond line numbers, cat can also reveal hidden but significant whitespace characters like tabs and new lines.
This can help identify irregular indents or trailing spaces which might break code execution.
Show special characters with cat -TET:
$ cat -TET test.py
1^Iimport math$
2$
3^Idef calc_area(radius):$
4^I area = math.pi * (radius ** 2)$
Here you can clearly see the tab characters (^I) and newlines ($) that are usually invisible.
Number Lines in Reverse Order
Reading code from the bottom up sometimes offers fresh perspective.
You can number lines in reverse via tac:
$ tac test.py | cat -n
4 print("Done")
3 calc_area(5)
2
1 def calc_area(radius):
This helps in tracking variable initialization and usage flows.
Focus on Line SubRanges
Narrowing down specific sections is key when dealing with large outputs.
To extract only certain line numbers ranges, use head and tail:
$ cat -n test.log | head -n 20 | tail -n 10
11 Lorem ipsum entry 1
12 Lorem ipsum entry 2
13 Lorem ipsum entry 3
14 Lorem ipsum entry 4
15 Lorem ipsum entry 5
16 Lorem ipsum entry 6
17 Lorem ipsum entry 7
18 Lorem ipsum entry 8
19 Lorem ipsum entry 9
20 Lorem ipsum entry 10
You can tweak the ranges to isolate suspicious activity when monitoring logs for intrusion analysis.
Beginning Line Numbers from Arbitrary Offset
By default cat -n starts counting from 1. But you may need numbering aligned to external references using offsets.
Specify a custom first line number with –number-nonblank:
$ cat -n --number-nonblank=100 test.txt
100 Hello
101 World
This allows correlating code lines with line indices from stack traces and debug logs.
Handle Multi-Byte Characters in UTF-8 Files
Cat can miscount lines in UTF-8 files containing multi-byte characters. Fix this with LC_ALL=C:
$ LC_ALL=C cat -n testfile.txt
This ensures multi-byte characters are read one byte at a time rather than potentially being counted as multiple lines.
Proper Unicode line counting is essential when dealing with globalized software containing non-ASCII text.
Cat -n Alternatives Worth Considering
So far we focused exclusively on cat for numbering lines. However, developers should also consider certain alternatives that can enrich functionality in specialized use cases:
nl – Number Lines from Files
The nl command is designed expressly for numbering lines and supports advanced formatting.
Benefit highlights:
- Custom numbering schemes (a1, a2 or i, ii, iii etc)
- Multi-column output with independent numbering per column
- Built-in offsets and padding configurations
Downsides:
- Not installed by default on most Linux distros
- Requires more typing for common cases
If you routinely work with legal documents, literature or test specifications where multi-scheme numbering is mandatory, nl has you covered.
grep -n – Print Line Numbers for Matching Lines
Grep is perfect for searching across files and directory trees. Combine it with -n to show line numbers for matching lines:
$ grep -n "RuntimeError" *.py
script1.py:204:RuntimeError: No active exception to reraise
script2.py:97:RuntimeError: Event loop stopped before Future completed.
You get filtered output containing only lines relevant to the search term along with their location markers.
This works for any text match – error messages, API calls, regex patterns etc.
Downsides are the need to always specify a search term and reduced parsing context due to missing non-matching lines.
Putting It All Together: A Cat -n Cheat Sheet
After covering so much ground across practical examples, command options and even alternative tools, let‘s consolidate the key techniques into an handy cheat sheet you can use for quick reference:
Number all lines in file.py
cat -n file.py
Number only non-blank lines
cat -b file.py
Number lines across multiple files
cat -n file1.txt file2.txt file3.py
Print line numbers reverse from bottom
tac file.py | cat -n
Extract line number digits only
cat -n file.py | awk ‘{print $1}‘
Format line numbers for easy parsing
cat -n file.txt | awk ‘{printf "%4s: ",$1}‘
Number lines from arbitrary offset
cat -n --number-nonblank=100 file.py
Handle multi-byte chars in UTF-8 files
LC_ALL=C cat -n file.py
Reveal special characters like tabs and newlines
cat -TET file.py
I hope this cheat sheet gives you a quick reference to apply cat‘s numbering versatility across your Linux-based coding and administration tasks.
Conclusion
The cat command is clearly far more powerful than its humble reputation suggests. Beyond simply displaying files, features like the -n option provide invaluable visibility for dissecting code and debugging complex issues.
In this guide aimed at developers, we covered practical applications of cat -n for analyzing stack traces, tracing execution flows, inspecting program output and much more. You should now have a firmer grasp of applying cat for your daily needs.
We also explored more advanced invocation patterns leveraging piping, redirection, command chaining and formatting options. Examples here revealed techniques to isolate suspicious log entries, correlate error reports with code lines and handle multi-byte encodings.
Finally, I presented alternatives like nl and grep -n so you can make informed choices for specialized use cases. The cheat sheet consolidates the best practices into an at-a-glance reference.
With 40+ years of continued relevance under its belt, the versatility of cat -n highlighted here clearly demonstrates why it remains an essential part of any serious Linux user‘s toolkit in the cloud-native age.
I hope you found this guide helpful. Do share any other handy cat -n tricks in the comments!


