Read File Contents

Quote

“The most effective debugging tool is still careful thought, coupled with judiciously placed print statements.”

Brian Kernighan, Unix for Beginners (1979)

Choose the first read

  • Small config or script: cat or Get-Content.
  • Unknown log: check size or line count first, then inspect with head, tail, Get-Content -TotalCount, or Get-Content -Tail.
  • Live log: tail -F on Linux, Get-Content -Wait -Tail 0 in PowerShell.
  • Known error pattern: grep -n -C or Select-String -Context.

Linux

Linux | bounded reads

Use bounded reads first so you can confirm structure and recent activity before you search or follow a file.

cat is appropriate when the file is small and you actually want the full contents on standard output. For unknown logs, treat cat as the last choice rather than the first.

Run the commands in this section to print a small file with cat.

cat /tmp/elysium-reading-demo/app.conf
APP_ENV=prod
PORT=8080
LOG_LEVEL=info

Read the first lines with head -n

head is the safer first look when you need schema, headers, or the opening lines of a file. If you only need a CSV header row, drop the count to 1.

Run the commands in this section to read the first lines with head -n.

head -n 3 /tmp/elysium-reading-demo/data.csv
symbol,price,volume
AAPL,214.32,1200
MSFT,428.10,900

Read the last lines with tail -n

tail is the quick way to inspect recent log activity without paging through the entire file. It is usually the first bounded read on an append-only log.

Run the commands in this section to read the last lines with tail -n.

tail -n 2 /tmp/elysium-reading-demo/pipeline.log
2026-04-14 14:24:03 ERROR [loader.ohlcv] Deadlock detected in writer
2026-04-14 14:24:04 INFO  [loader.ohlcv] Batch complete

Linux | inspect unknown logs before deeper analysis

Before you stream or search an unfamiliar log, confirm its size and then narrow the scope with targeted reads.

Check file size with ls -lh

File size tells you whether a full-file read is cheap or reckless. On a large file, switch to bounded reads and targeted search immediately.

Run the commands in this section to check file size with ls -lh.

ls -lh /tmp/elysium-reading-demo/pipeline.log
-rw-r--r-- 1 alex alex 437 Apr 14 13:09 /tmp/elysium-reading-demo/pipeline.log

Count newline-terminated records with wc -l

wc -l counts newline characters, which makes it a fast way to estimate record count before you decide how aggressively to inspect the file. A final line without a trailing newline is not counted the way many editors display it.

Run the commands in this section to count newline-terminated records with wc -l.

wc -l /tmp/elysium-reading-demo/pipeline.log
7 /tmp/elysium-reading-demo/pipeline.log

Show line numbers and surrounding context with grep -n -C

When you already know the pattern, grep -n -C gives you the hit, its line number, and a bounded amount of context around it. That is usually enough to decide whether you need a longer time-window extract.

Run the commands in this section to show line numbers and surrounding context with grep -n -C.

grep -n -C 1 'ERROR' /tmp/elysium-reading-demo/pipeline.log
3-2026-04-14 14:24:00 WARN  [loader.ohlcv] Retrying after timeout
4:2026-04-14 14:24:01 ERROR [loader.ohlcv] Connection timeout after 30s
5-2026-04-14 14:24:02 INFO  [loader.ohlcv] Retry succeeded
6:2026-04-14 14:24:03 ERROR [loader.ohlcv] Deadlock detected in writer
7-2026-04-14 14:24:04 INFO  [loader.ohlcv] Batch complete

Slice a known time window with awk

If the interesting period is already known, an awk range pattern is the simplest way to isolate that window without opening the rest of the file.

Run the commands in this section to slice a known time window with awk.

awk '/^2026-04-14 14:24:00/,/^2026-04-14 14:24:02/' /tmp/elysium-reading-demo/pipeline.log
2026-04-14 14:24:00 WARN  [loader.ohlcv] Retrying after timeout
2026-04-14 14:24:01 ERROR [loader.ohlcv] Connection timeout after 30s
2026-04-14 14:24:02 INFO  [loader.ohlcv] Retry succeeded

Linux | follow live logs

Once the bounded reads tell you that the file is the right target, switch to follow mode for ongoing activity.

Follow a rotating log with tail -F

Use tail -F when the writer may rotate or replace the file under the same name. The captured output below shows the reopen event, which is exactly why -F is safer than plain -f for production logs.

Rotation-safe follow mode

GNU tail -f follows the file descriptor by default, which can leave you attached to the old inode after a rename or log rotation. tail -F switches to name-following with retry, so the reader can reopen the path when the log disappears and reappears.

Run the commands in this section to follow a rotating log with tail -F.

tail -n 0 -F /tmp/elysium-reading-demo/live.log
2026-04-14 14:25:00 INFO appended before rotation
tail: '/tmp/elysium-reading-demo/live.log' has become inaccessible: No such file or directory
tail: '/tmp/elysium-reading-demo/live.log' has appeared;  following new file
2026-04-14 14:25:01 INFO resumed after rotation
2026-04-14 14:25:02 WARN retrying on new file

PowerShell

PowerShell | bounded reads

PowerShell exposes the same core reading patterns, but the pipeline carries string objects and MatchInfo objects instead of plain text lines alone.

Default Get-Content is the PowerShell equivalent of a basic file read. It emits one string per line, which means later pipeline steps still work line by line.

Run the commands in this section to print a small file with Get-Content.

Get-Content (Join-Path $env:TEMP 'elysium-reading-demo\app.conf')
APP_ENV=prod
PORT=8080
LOG_LEVEL=info

Read the first lines with -TotalCount

Get-Content uses -TotalCount for the bounded “read the first N lines” case. Use 1 when you only need the header row.

Run the commands in this section to read the first lines with -TotalCount.

Get-Content (Join-Path $env:TEMP 'elysium-reading-demo\data.csv') -TotalCount 3
symbol,price,volume
AAPL,214.32,1200
MSFT,428.10,900

Read the last lines with -Tail

-Tail is the direct equivalent of tail -n. It is the safest way to inspect the newest log lines without materializing the full file.

Run the commands in this section to read the last lines with -Tail.

Get-Content (Join-Path $env:TEMP 'elysium-reading-demo\pipeline.log') -Tail 2
2026-04-14 14:24:03 ERROR [loader.ohlcv] Deadlock detected in writer
2026-04-14 14:24:04 INFO  [loader.ohlcv] Batch complete

Use -Raw only when you need one string

-Raw changes the shape of the result from line-by-line output to a single string object. That is useful for whole-file parsing, but it is the wrong default for large log inspection.

Run the commands in this section to use -Raw only when you need one string.

(Get-Content (Join-Path $env:TEMP 'elysium-reading-demo\pipeline.log') -Raw).GetType().FullName
System.String

PowerShell | follow and search logs

For ongoing logs, follow the file as it grows. For known patterns, switch to Select-String so the result includes match metadata instead of plain text alone.

Follow appended lines with -Wait

-Wait keeps reading as new lines arrive. Pair it with -Tail 0 when you only want future writes instead of replaying the current file contents first.

FileSystem-only follow behavior

Get-Content -Wait works only on FileSystem drives, polls once per second, cannot be combined with -Raw, and stops if the file is deleted. It follows appended lines well, but it is not a path-reopen equivalent to tail -F.

Run the commands in this section to follow appended lines with -Wait.

Get-Content -Path (Join-Path $env:TEMP 'elysium-reading-demo\live.log') -Wait -Tail 0
2026-04-14 14:25:00 INFO appended line
2026-04-14 14:25:01 WARN retrying

Search with context using Select-String

Select-String is the right tool when you need the match plus surrounding lines. Converting each result to a string keeps the example readable while still showing line numbers and context.

Run the commands in this section to search with context using Select-String.

Select-String -Path (Join-Path $env:TEMP 'elysium-reading-demo\pipeline.log') -Pattern 'ERROR' -Context 1,1 | ForEach-Object { $_.ToString() }
  C:\Users\aperi\AppData\Local\Temp\elysium-reading-demo\pipeline.log:3:2026-04-14 14:24:00 WARN  [loader.ohlcv] Retrying after timeout
> C:\Users\aperi\AppData\Local\Temp\elysium-reading-demo\pipeline.log:4:2026-04-14 14:24:01 ERROR [loader.ohlcv] Connection timeout after 30s
  C:\Users\aperi\AppData\Local\Temp\elysium-reading-demo\pipeline.log:5:2026-04-14 14:24:02 INFO  [loader.ohlcv] Retry succeeded
> C:\Users\aperi\AppData\Local\Temp\elysium-reading-demo\pipeline.log:6:2026-04-14 14:24:03 ERROR [loader.ohlcv] Deadlock detected in writer
  C:\Users\aperi\AppData\Local\Temp\elysium-reading-demo\pipeline.log:7:2026-04-14 14:24:04 INFO  [loader.ohlcv] Batch complete

Count matching lines with Select-String

If you only need magnitude before you inspect full context, count the MatchInfo results first and expand later only when the number justifies it.

Run the commands in this section to count matching lines with Select-String.

(Select-String -Path (Join-Path $env:TEMP 'elysium-reading-demo\pipeline.log') -Pattern 'ERROR').Count
2

Cross-references