Forgotten bash commands
A few bash commands with a special meaning that deserve more use.
pushd / popd - the directory stack
Instead of cd-ing back and forth, push directories onto a stack and pop back
out. dirs -v shows the stack with indices.
$ pushd /var/log # cd to /var/log AND remember where you were
$ pushd /etc # now on /etc; stack: /etc /var/log ~
$ dirs -v # list the stack
$ popd # pop the top, back to /var/log
$ cd - # simpler: toggle between the last two dirs
curl cheat.sh
cheat.sh returns concise, example-first help for a command:
$ curl cheat.sh/tar # cheatsheet for tar
$ curl cheat.sh/tar/extract # narrow to a sub-topic
Handy alias (see also .zshrc & .bashrc modifications):
alias ch='curl cheat.sh/$0' # then just: ch tar
progress
Show progress for a running cp/mv/dd (install with
dnf install -y progress):
$ cp big.iso /mnt/ & progress -mp $! # -m monitor, -p the just-started PID
watch
Re-run a command every N seconds and show the latest output - good for watching a file appear or a value change:
$ watch -n 0.1 ls console.txt # poll every 0.1s
$ watch -d 'rpm-ostree status' # -d highlights what changed between runs
history shortcuts
The shell remembers your last commands and their arguments - stop retyping:
$ sudo !! # re-run the LAST command, prefixed with sudo
$ mkdir newdir && cd !$ # !$ = last argument of the previous command
$ cp file.txt /backup/ && cd $_ # $_ also = last arg (works mid-script)
$ ^typo^fixed # re-run last command, replacing "typo" with "fixed"
$ !curl # re-run the most recent command starting with "curl"
# Ctrl+R : reverse-search history as you type
# Ctrl+X Ctrl+E : open the current command line in $EDITOR
brace expansion
The shell expands {...} before running anything - great for backups and bulk
creation:
$ cp config.yaml{,.bak} # -> cp config.yaml config.yaml.bak
$ mv report-{2023,2024}.csv # rename report-2023.csv -> report-2024.csv
$ mkdir -p project/{src,test,docs} # create three directories at once
$ echo {1..5} # 1 2 3 4 5
$ touch file-{01..10}.txt # zero-padded ranges work too
process substitution
<(cmd) makes a command’s output look like a file - perfect for diffing two
commands without temp files:
$ diff <(sort a.txt) <(sort b.txt)
$ diff <(rpm -qa | sort) <(ssh host 'rpm -qa | sort') # compare package sets
$ comm -12 <(sort a) <(sort b) # lines common to both
text wrangling
$ tac file.log # cat in reverse (last line first)
$ column -t -s, data.csv # align CSV into neat columns
$ paste -d, col1.txt col2.txt # join files side by side
$ shuf -n1 list.txt # pick a random line
xargs
Build and run commands from stdin - {} is each item, -P runs in parallel:
$ find . -name '*.tmp' | xargs rm
$ ls *.png | xargs -I{} mv {} images/{}
$ cat urls.txt | xargs -P4 -n1 curl -O # 4 downloads at a time
tee
Write to a file and stdout at once - and the classic trick for writing a root-owned file without a root shell:
$ make 2>&1 | tee build.log
$ echo "net.ipv4.ip_forward=1" | sudo tee /etc/sysctl.d/99-fwd.conf
small but handy
$ timeout 5 ping example.com # give up after 5 seconds
$ yes | dnf install foo # auto-answer "y" to every prompt
$ seq 1 2 10 # 1 3 5 7 9 (start step end)
$ mktemp -d # create a safe temp directory
$ disown -h %1 # keep a background job alive after logout
trap - clean up on exit
Run cleanup whenever a script exits, even on error or Ctrl+C:
tmp=$(mktemp -d)
trap 'rm -rf "$tmp"' EXIT # always removes the temp dir on exit
watching progress
pv (pipe viewer) shows a live progress bar, throughput and ETA for anything
flowing through a pipe (dnf install -y pv):
$ pv big.iso | gzip > big.gz # progress bar + ETA while compressing
$ pv /dev/zero > /dev/null # measure raw throughput
$ tar czf - /data | pv | ssh host 'cat > data.tgz' # progress over the network
For a quick spinner in your own script while a slow job runs:
slow-task & pid=$!
while kill -0 $pid 2>/dev/null; do
for c in '|' '/' '-' '\\'; do printf "\r%s working..." "$c"; sleep 0.1; done
done; printf "\rdone \n"
timers and stopwatches
$ time some-command # how long a command took (real/user/sys)
$ time read # crude stopwatch - press Enter to stop
$ sleep 25m && tput bel # a 25-min pomodoro; rings the terminal bell
$ for i in {5..1}; do printf "\r%2ds " "$i"; sleep 1; done; echo "go!" # countdown
$ tty-clock -c -C4 # a centered terminal clock (needs tty-clock)
terminal toys
Pure fun. Most are separate packages - install with dnf install <name>:
$ cmatrix # the Matrix "digital rain"
$ sl # a steam locomotive chuffs by when you mistype "ls"
$ fortune | cowsay | lolcat # a random quote, from a cow, in rainbow
$ figlet "HELLO" # big ASCII-art banner text
$ pipes.sh # animated pipes screensaver
$ cbonsai -l # a slowly growing bonsai tree
$ asciiquarium # an ASCII aquarium
$ nyancat # the nyan cat, forever
$ neofetch # system info next to your distro logo