Practical Linux Tricks for the Aspiring Hacker

A curated list of fanciful Linux tricks I use to bolster my command-line prowess and activate Sage Mode.

This is a collection of commands I've picked up over the last few years, which I've found immensely useful. My favourite ones are probably:

  • less: search/filter on a file or long text
  • ^r: reverse search
  • !$: last argument of previous command

By "favourite", I mean I've used these commands a lot, and they've drastically increased my productivity.

Cool Stuff

Control (^) Commands

^c # Duh.
^d # Exit / EOF.

^r # Reverse search: for those long commands stashed in history.

Ternary Expression

[ 1 -eq 1 ] && echo 'true' || echo 'false'
# true

Clear screen. Useful for graphical hiccups.


Run shell script without chmod +x.

. ~/.zshrc  # Dot command.
source ~/.zshrc

Tree view of files.



Double-Quotes vs. Single-Quotes

  • Double-quotes allow variable expansion and command substitution.
  • Single-quotes don't. Prefer single-quotes for simple strings.
echo "$((1+1))" "$SHELL"
# 2 /bin/zsh

echo '$((1+1))' '$SHELL'
# $((1+1)) $SHELL

Multi-Line / Escape
Prefix the string with $.

echo $'...'

Escape Single-Quotes


Multi-Line Strings.

echo $'1\n2\n3'
# 1
# 2
# 3

Find words containing 't in comma-separated line.

echo -n $'can\'t,don\'t,I\'ll,I\'m,won\'t' | awk -vRS=, $'$0 ~ /\'t/'
# can't
# don't
# won't

Previous-Command Tricks

  • $?: exit code of previous command
    • By convention, 0 means no error. Non-0 implies an error occurred.
  • !!: previous command
  • !$ or $_: last argument of previous command


Retry with sudo.

mkdir /var/tmp/lol
# Permission denied.
sudo !!
# Yay!

Found an interesting directory, but forgot to cd.

ls long/path
cd !$
# → cd long/path

Rename file in folder from file.txt to

cat long/path/file.txt
mv "!$" "$(dirname !$)/"
# → mv long/path/file.txt long/path/

Other Useful Commands (stolen from here)

  • !!:n - nth argument from previous command
  • !^ - first argument (after the program/built-in/script) from previous command
  • !* - all arguments from previous command
  • !n - command number n from history
  • !pattern - most recent command matching pattern
  • !!:s/find/replace - last command, substitute find with replace


< out.txt # Read from file (to stdin).
> out.txt # Write to file (from stdout).
>> out.txt # Append to file (from stdout).
2> out.txt # Write to file (from stderr).
&> out.txt # Redirect all output.
&> /dev/null # Redirect everything into the void.
2>&1 # Redirect stderr to stdout.

>& # Same as `&>`.

Powerful Utilities

  • awk: filter lines, filter columns, math, scripting, etc.
  • sed: filter/replace text
  • grep: filter lines
  • cut: filter columns
  • tr: replace/remove characters
  • wc: count characters/bytes/words
  • find: find files in folder, execute command for each file with -exec
  • xargs: feed arguments into commands, simple cmdline multi-processing

I won't cover too much of these commands here, as tons of articles already cover them. And you can browse examples online or in their man pages.

awkward things

awk - Cut

awk '$0=$3' # Cut third field.
awk '{print $3}' # Print third field. (Pretty much same as the command above.)

# Use ',' as field delimiter, e.g. for CSVs.
awk -F, '{print $3}'
# or use the script variable `FS` (Field Separator).
awk -v FS=, '{print $3}

awk - Filtering

awk '$1 == 1' # Filter lines with first field = 1.
awk '$0 ~ /^foo/' # Filter lines with regex.

awk - Math

awk '{$1 += 5}1' # Add 5 to the first arg, then print the line.

seq 1 3 | awk '{$1 += 5}1'
# 6
# 7
# 8

awk - Scripting

awk '{print "booyah",$1,"yahoo"}'
# awk also has variables, if, for, while, arrays, etc.

Script variables. (Useful for configuring row/column delimiters.)

  • RS: Record Separator (rows)
  • FS: Field Separator (columns)
  • ORS: Output Row Separator
  • OFS: Output Field Separator
  • NR: Record Number (current row, 1-indexed) [read-only]
  • NF: Number of Fields [read-only]


Useful Flags

# case-insensitive
# regex
# non-match (inVert)


xargs is a versatile command-line utility that allows efficient execution of commands from, making it a powerful tool for automation and batch processing.

Interesting options:

-P <n> # max procs
-n <n> # num args
-I {}  # pattern to insert into command


Combine multiple lines into 1 line.

echo $'1\n2\n3' | xargs 
# Output: 1 2 3 (no newline)

Multi-Processing: Execute ./ <file> on multiple files, with at most 4 processes.

cat files.txt | xargs -P 4 -n1 ./

Multi-Processing: Port Scan with Ports 1-1000 Through proxychains.

seq 1 1000 | xargs -P 50 -I{} proxychains4 -q nmap -p {} -sT -Pn --open -n -T4 --oN nmap.txt --append-output

Other Utilities

basename ~/.bashrc # .bashrc     # Filename, without path.
dirname ~/.bashrc  # /home/bob/  # Path to file.

Directory Stack

pushd # Push current directory, for easier returning.
popd  # Return to directory on top of stack.

pushd/popd Example

cd ~/a/b/c
pushd deep/nested/directory
# Jump to `deep/nested/directory`, push `~/a/b/c` into the stack.
cd ../../jump/around/some/more
cd ../../and/a/little/more
popd  # Return to `~/a/b/c`.


less is a powerful text viewer (read-only), with capabilities to navigate, search, and filter lines in a file or long text.

less - Nice Options

less file.txt

# Renders ANSI colors.
less -R file.txt

# Pager search becomes case insensitive.
less -I file.txt

# Line numbers.
less -N file.txt

less - Navigation

j # Line down.
k # Line up.
f # Page down.
b # Page up.
d # Half-page down.
u # Half-page up.

g # Go to start of file.
G # Go to end of file.

<n> g # Go to nth line.

# Go to the n% line of the file.
<n> p
20p 40p 50p 80p

# What's the current line?

less - Search / Filtering

# Search (regex enabled).
/ <pattern>
# For case-insensitive search, use `less -I`.

# Navigate search results: next/prev result.

# Filter lines by search.
& <pattern>
# Filter NON-MATCHING lines
& ! <pattern>
# Clear filter.
& <enter>

less - Scrolling

Personally, I prefer less+F over tail -f.
Use ^c to exit the feed.

# Continuous feed (e.g. for streams of data)

less - Working with Multiple Files

less also works with multiple files passed in the command line, e.g. less *.txt.

# Next file.
# Previous file.

More commands in man less.


fg/bg - "I'll be back."

Shells allow you to move processes between the foreground (which accepts interactive input) and background (to run things which don't require input).

^z # Push process to background (and pause it).
bg # Start background process.
fg # Bring most recent background process into foreground.
fg 2 # Bring job 2 into foreground.
jobs # View background jobs.

^c # Good ol' ctrl-c stops the process in fg.
kill <pid> # Kill process with given process ID.

# Start a command in the background.
<cmd> &


Start an HTTP server on port 8080.

python -m http.server 8080 &
# [1] 17999

The process is started in the background with job number 1, PID 17999.

To kill the process:

# or
kill 17999

Process ID (PID) and Job Number are two different things.

  • PIDs apply to all users in the entire system, and are assigned by the kernel.
  • Job Numbers apply to the current shell, and are numbered linearly from 1 onwards.

View Running Procs

ps aux

Combine with grep/less for filtered results.



# IP
ifconfig tun0

# Open Ports/Sockets
netstat -anp
# -a: all sockets
# -n: numeric addresses
# -p: associated processes


# Initiate a connection.
nc 8080

# Listen for a connection.
nc -nlvp 4444

# Listen persistently (keep listening after disconnect).
nc -nklvp 4444

Download Files


# Quick download.
wget <url>

# Save to specific location.
wget <url> -O filename.txt

# Download silently (no progress), and display in less.
wget <url> -s | less


curl <url> -s | less

# Use jq to format JSON.
curl -s | jq | less

Upload Files


python -m uploadserver
  • By default, uploadserver starts a server at port 8000.
  • Get our IP from ifconfig.


curl -F files=@file1.txt -F files=@file2.txt

git gud

Git commands for completeness.

# Make new branch.
git checkout -b <name>

# Checkout commits in tree before HEAD.
git checkout HEAD~1  # 1 commit before.
git checkout HEAD~10 # 10 commits before.

# Checkout commit from parent.
git checkout HEAD^  # 1 commit before (from parent 1, base).
git checkout HEAD^2 # 1 commit before (from parent 2, target).

# Store changes locally.
git stash
git stash pop

# Clean edited files.
git reset [--hard]
# --hard removes unstaged files.

# View changes.
git diff | less
git diff <file> # See change in specific file.

# Jump through commits (to find, say, the cause of a bug).
git bisect [start|reset|good|bad|skip]

git tree

# Command-line git tree from git log.
git log --graph --abbrev-commit --decorate --format=format:'%C(bold blue)%h%C(reset) - %C(bold green)(%ar)%C(reset) %C(white)%s%C(reset) %C(dim white)- %an%C(reset)%C(bold yellow)%d%C(reset)' --all

# More detailed git-tree 
git log --graph --abbrev-commit --decorate --format=format:'%C(bold blue)%h%C(reset) - %C(bold cyan)%aD%C(reset) %C(bold green)(%ar)%C(reset)%C(bold yellow)%d%C(reset)%n''          %C(white)%s%C(reset) %C(dim white)- %an%C(reset)' --all

# Add them as git aliases in ~/.gitconfig or script aliases in ~/.bashrc.
# See

Fun watch: So You Think You Know Git?


Haha. Nope.

Not covering that here.

Hacky Hack Hack

Generate Bytes

Buffer overflow for fun and profit.


echo -n '\x01\x02'

echo -n '\x41' | xxd
00000000: 41                     A

perl (good for repetitive sequences)

perl -e 'print "\x41"x4 . "\x42\x43"' | xxd
00000000: 4141 4141 4243         AAAABC

I've mentioned this elsewhere, but I'll repeat it here: I don't recommend using Python 3 to generate strings on-the-fly, as its string/byte-string mechanics are unintuitive. Prefer perl or echo instead.

For example: python -c 'print("\xc0")' prints \xc3\x80 (À) instead of \xc0. Why? Because the Python string "\xc0" is interpreted as U+00C0, which is \xc3\x80 in UTF-8.

assert '\xc0'.encode() == b'\xc3\x80'

Printing bytes in Python is difficult to do concisely.

Share on

Commenting has vanished into a blackhole and shall return some time in the future (or past?)! Time paradoxes not guaranteed. If you have any feedback or suggestions, please direct your subspace frequencies to the contact form. Thanks!