> ## Content Index
> Fetch the complete content index at: https://www.workroom-productions.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# cat, head and tail for Testers
- URL: https://www.workroom-productions.com/cat-head-and-tail-for-testers/
- Published: 2025-06-19T13:52:06.000Z
- Updated: 2025-06-19T13:52:06.000Z
- Description: Line processors, file slicers, used everywhere, hidden powers.
- Author: James Lyndsay
- Tags: Tools, Articles, #PlayTime

*Ubiquitous commandline tools. Text unfinished, still useful.*

These three small tools give you back what you give them, line by line. `head` gives you the top 10 lines, `tail` gives you the bottom 10 lines. And `cat` gives you all the lines in a great waterfall of stuff. We'll come back to `cat`.

The context these are initially useful in is the context of handling text files without a neatly scrollable editor, and possibly without the memory to actually hold the whole file. Want to see what's in `my_vast_list.csv`? Use `head my_vast_list.csv` and you can get a clue without reading the whole thing. Want to see the most recent lines glommed on the end of `awful.log`? Use `tail awful.log` and there they are without needing to load the file or scroll through it.

You can use `cat this.txt that.txt` to lump two files together: `cat` is made to *concatenate* files. But you'll more often find it used in the wild with just one input. That's because concatenating a file with nothing does nothing to the file, so `cat` hands it back to you, line by line – the file has become a stream.

Streams are managed line-by-line, which is memory-efficient. Work scales with more time, rather than more hardware. Unix is very stream-y – all the connections between tiny tools with `|`and `>` are built on streams. `cat` opens the door to processing files with the power of those commandline tools.

## `cat` to stream

## 

*I keep rewriting this – the basic summary is that `cat` is handy enough to be used all over the place, but that plenty of that use is not necessary good use!*

`cat`'s broad usefulness is that it allows something to be processed line by line. Why write `for i = 0 to lines_in(file); do something to line(i); append that to output` if you can write `cat file | something > output`.

However, this ubiquitousness also leads to [Useless Use of cat](https://stackoverflow.com/questions/11710552/useless-use-of-cat). You might instead write `something < file >> output`. 

Here are some examples:

- use `cat myresults.md | grep "FAIL"` to pick out all the lines marked "fail" (or use `grep "FAIL" myresults.md`
- use `cat myresults.md | grep "FAIL" > fails.md` to put those lines in a file
- use `cat test_whatever.py | grep "test_"` to pick out

also

- use `cat stuff > /tmp/before.txt` to copy a file
- AVOID THIS: To swiftly create a file without bothering with an editor, `cat > myfile.txt`, type away (you're putting a stream into `cat` and it's streaming it into a file) and hit ctrl+d when done. It's neat, but it overwrites `myfile.text` irrevocably and I've kicked myself for doing it. However...
- `cat` is a regularly used in "[here-documents](https://en.wikipedia.org/wiki/Here%5Fdocument)", which I see more commonly using LLMs than I did in my time doing ops and environments. Look out for `cat <<EOF > *something*`, followed by lines with an `EOF` at the end.

## `cat` tricks

While it has less-used features that can be very handy, 

- Number the lines with `cat -n boogaloo.txt`. Number just the non-blank ones with `cat -b boogaloo.txt`.
- Skip multiple blank lines with `cat -s boogaloo.txt` – and you can combine that with `-n` or `-b` for counts.
- Some characters found in files can't be displayed in a terminal – at best your days gets choppy or beepy, at worst your setup is changed in an unspeakable and unfindable way. Pipe output like this `nastyout | cat -tve` to make it sane.
- Split that up to look for invisible problems in text. In `cat -tve` above, `-t` shows tabs as `^I`, `-e` shows line-ends as `$` and `-v` shows non-printing characters in a printable (but obscure) way. Use it to spot places where tabs should be spaces, where line-ends aren't where you want, or where some sossidge has furkled your data.
- `cat` is made to *concatenate* files. It does the job well. Use it as `cat me.txt you.txt` to fill your terminal, or pipe it somewhere useful `cat us.txt them.txt > everyone.txt`

## Using and abusing `cat`

- `cat` regularly pours gigabytes of text into my terminal, typically when I don't know what I'm looking at. `cat *whatever* | less`lets me step through it using the `less` paginator. Or I could just `less *whatever*`, though by some unthinking habit I use `cat`.

## Shared behaviours

- You can use `cat`, `head` and `tail` in combination with others, as input or as output.
- You can use all these with file patterns
  - `head -n 3 *` will show you the tops of all the files (with a`==> filename <==` at the top of each).
  - `tail -n 5 *.log` will show you the last `5` lines in each file in the local directory ending `.log`
  - `cat *.log` will show the contents of all the files ending `.log`. If they all have the same serial info at the start, you can at a pinch `cat *.log | sort` to interleave them.

### Shared with `head` and `tail`

- You can set the size of `head` and `tail` with `-n`, so `head -n 5 awful.log` shows the top 5 lines of `awful.log`. Both default to 10.
- You can limit the number of characters output with `-c`: handy if producing something of a particular size.
- You can use `-q`uiet to never show filenames (handy if passing to processing) and `-v`erbose to always show filenames (handy if reading and confused)

## Back to `head` and `tail`

- You can aim the output of something into the input of one of these. If `grep diddley doo.txt` shows all lines containing `diddley`, then `grep diddley doo.txt | head -n 5` shows the first 5 `diddley`s.
- You can `tail -f` a log – and as the log grows (from the bottom, naturally), that changes what you see. `-f` is for ***f***ollow. Use `-F` to retry: good when the file doesn't exist, or may vanish.
- Want to work with something of a particular size? Use `head`/`tail` with `-n` for number of lines, `-c` for number of characters.
- Want something inbetween two limits? Use `head -n 10 | tail -n 3` to see lines 7 to 10\. More precise – want just line 453? `head -n 453 | tail -n 1`
- Just want to see the start of *somecommand*? Throw it to head `somecommand | head` . Just want the last lines of message? Throw it to tail `somecommand | tail`(?jlcheck this for long output). This gets used with `curl` and `wget` when grabbing stuff from a URL, with SQL commands when one hasn't bothered to restrict the size of the output, and more.

## Oddnesses

Careful of using `-n` vs `-*somenumber*` i.e. `head -n 3` and `head -3`. They do the same, but `-3` is considered obsolete. 

Note that `head -3` and `head -n 3` may do the same thing, but `head -n +3` and `head +3` don't do the same things – on some systems I believe that `head -n +3` starts from the third line... on my Mac with a bash shell, it doesn't. I don't know how to do (say) "from the 5th line to the end" without piping a `head` to a `tail` and that means knowing the file length.

Note that the man for `tail` says "**\-n** +NUM to skip NUM-1 lines at the start". I don't know what this means – at the start of *what*; the input file, or the result.

## `man` pages

## 

[cat(1) - Linux manual page![](https://storage.ghost.io/c/7e/30/7e30843b-2abb-494a-ab80-0e931d8ae9a9/content/images/icon/faviconV2-4)Linux manual page![](https://storage.ghost.io/c/7e/30/7e30843b-2abb-494a-ab80-0e931d8ae9a9/content/images/thumbnail/TLPI-front-cover-vsmall-3.png)](https://www.man7.org/linux/man-pages/man1/cat.1.html)

[head(1) - Linux manual page![](https://storage.ghost.io/c/7e/30/7e30843b-2abb-494a-ab80-0e931d8ae9a9/content/images/icon/faviconV2-3)Linux manual page![](https://storage.ghost.io/c/7e/30/7e30843b-2abb-494a-ab80-0e931d8ae9a9/content/images/thumbnail/TLPI-front-cover-vsmall-2.png)](https://www.man7.org/linux/man-pages/man1/head.1.html)

[tail(1) - Linux manual page![](https://storage.ghost.io/c/7e/30/7e30843b-2abb-494a-ab80-0e931d8ae9a9/content/images/icon/faviconV2-2)Linux manual page![](https://storage.ghost.io/c/7e/30/7e30843b-2abb-494a-ab80-0e931d8ae9a9/content/images/thumbnail/TLPI-front-cover-vsmall-1.png)](https://www.man7.org/linux/man-pages/man1/tail.1.html)

---

 because it does a simple thing: it writes out what you give it.

If you give it *one* file, it lists it back for you.

Think of these tools as acting on something as *rows* – you can give each a file, a bunch of files, or a stream.

- `cat` shows (and can transform) all the rows, in order.
- `head` shows rows from the top, in order
- `tail` shows rows from the bottom, in order

That's kind-of obvious for files, and that's not the only way to think of these tools.