The previous five lessons have given you the arsenal of commands; this one teaches you to wield it fast. It may look like a minor topic next to permissions or pipes, but it is not: in operations, the difference between someone who types every command from scratch and someone who reuses, corrects and chains in seconds is measured in hours of work per week. When srv-veloz-01 is down at three in the morning and you need to iterate over a chain of filters until you find the cause, that speed stops being a convenience and becomes real response capability.

Contents

  1. The command history and history
  2. History expansion: !!, !$ and company
  3. Incremental search with Ctrl-R
  4. Configuring the history: HISTSIZE, HISTCONTROL and friends
  5. Do not leave passwords in your history
  6. Line editing with readline
  7. Tab completion
  8. Job control: first contact
  9. Aliases for the Veloz Envíos day-to-day

  1. The command history and history

Bash stores every command you run in a numbered list, which it dumps into ~/.bash_history when the session closes.

history | tail -3
  514  chmod 600 ~/veloz-ops/etc/veloz-ops.conf
  515  ls -l ~/veloz-ops/bin/
  516  history | tail -3

Those numbers are the key to reusing commands. Common operations on the history:

Command Effect
history Lists the whole numbered history
history 20 Only the last 20
history | grep chmod Search earlier commands containing chmod
history -d 514 Delete one specific entry (for example, one that carried a key)
history -c Clear the history of the current session
history -a Flush to the file right now, without waiting for the session to close

A detail that surprises people: the history is written when the session closes, and if you have several terminals open, the last one to close can overwrite what the others wrote. The solution is in section 4.

  1. History expansion: !!, !$ and company

Bash can insert pieces of earlier commands into the current line through history expansion, which is triggered with !.

Shortcut Inserts
!! The whole previous command
!n Command number n from the history
!-2 The second-to-last command
!str The last command that started with str
!?str? The last command that contained str
!$ The last argument of the previous command
!^ The first argument of the previous command
!* All the arguments of the previous command

The star use of !! is recovering a command that failed for lack of privileges:

systemctl restart veloz-api    # → Failed to restart veloz-api.service: Access denied
sudo !!                        # expands to: sudo systemctl restart veloz-api

And !$ saves you retyping long paths, which is where most mistakes are made:

ls -l /srv/veloz/data/archive/2026/08/shipments-2026-08-03.csv
head -3 !$     # head -3 /srv/veloz/data/archive/2026/08/shipments-2026-08-03.csv

There is also the quick substitution ^old^new, which repeats the previous command changing the first occurrence of a string:

grep ERROR /var/log/veloz/app.log
^ERROR^WARN     # runs: grep WARN /var/log/veloz/app.log

It is perfect for fixing a typo without rewriting the line. A safety tip: with destructive commands, add the :p modifier (for print), which shows the expanded command instead of running it and leaves it in the history ready to be recalled with the up arrow. That way, !rm:p shows you the last command that started with rm without actually launching it.

  1. Incremental search with Ctrl-R

Expansion with ! is powerful, but it requires remembering. Ctrl-R does not: it opens an incremental backwards search that shows the match as you type.

(reverse-i-search)`issu': grep ',issue,' /srv/veloz/data/shipments.csv | cut -d, -f3
Key Action
Ctrl-R Start the search, or jump to the previous match
Ctrl-S Go to the next match (forwards)
Enter Run the command found
Right arrow or Ctrl-E Edit it before running
Ctrl-G Cancel and go back to an empty line

This is probably the shortcut you will use the most times in your whole professional life: typing three letters of a pipeline you wrote two days ago and getting it back whole.

A classic warning about Ctrl-S: in many terminals that combination is captured by XON/XOFF flow control and freezes the screen instead of searching. If that happens to you, Ctrl-Q unfreezes it. To free Ctrl-S permanently, add stty -ixon to your ~/.bashrc.

  1. Configuring the history: HISTSIZE, HISTCONTROL and friends

The behavior of the history is tuned with environment variables defined in ~/.bashrc (lesson 01-02):

Variable What it controls Recommended value
HISTSIZE Commands kept in memory during the session 10000
HISTFILESIZE Commands kept in the file ~/.bash_history 20000
HISTCONTROL Which commands are not stored ignoreboth
HISTIGNORE Command patterns to exclude "ls:cd:pwd:history:exit"
HISTTIMEFORMAT Timestamp on each entry "%F %T "

HISTCONTROL accepts three values that can be combined with ::

  • ignoredups: does not store a command if it is identical to the previous one.
  • ignorespace: does not store commands that start with a space.
  • ignoreboth: both at once. This is the usual option.

HISTTIMEFORMAT deserves special attention because it changes the output of history by adding the date of each command:

export HISTTIMEFORMAT="%F %T  "
history 2
  514  2026-08-03 11:22:41  chmod 600 ~/veloz-ops/etc/veloz-ops.conf
  515  2026-08-03 11:23:05  ls -l ~/veloz-ops/bin/

Knowing when you ran something is decisive when reconstructing an incident: it lets you correlate your actions with the timestamps in app.log.

And the configuration that solves the several-terminals problem:

shopt -s histappend                        # append to the file instead of overwriting it
PROMPT_COMMAND='history -a'                # flush after each command, not on close

With those two lines in your ~/.bashrc, each terminal adds its commands to the shared file immediately and none of them tramples the others.

  1. Do not leave passwords in your history

This section is short and critical. Everything you type ends up in ~/.bash_history, a plain text file. If you type mysql -u veloz -pMySecretKey123, that password is saved on disk, synced into the backups, and visible to anyone who gets into your account. Three defenses:

# 1. Prefix a space (requires HISTCONTROL with ignorespace)
 curl -H "Authorization: Bearer TOKEN123" https://api.veloz.local/envios

# 2. Delete the entry if you already typed it
history -d 514 && history -a

# 3. Better still: never have the credential on the command line
source ~/veloz-ops/etc/veloz-ops.conf   # the file with 600 permissions from lesson 02-03

Notice the leading space on the first line: it is deliberate, and it only works if HISTCONTROL includes ignorespace. The third option is the right one in the long run, and it is the reason why in 02-03 we protected veloz-ops.conf with 600 permissions: secrets live in a restricted file, not on the command line.

  1. Line editing with readline

Bash uses the readline library to edit the current line, with the same shortcuts as Emacs. No more moving character by character with the arrows:

Shortcut Action
Ctrl-A / Ctrl-E Go to the beginning / end of the line
Alt-B / Alt-F Move back / forward one word
Ctrl-U Delete from the cursor to the beginning
Ctrl-K Delete from the cursor to the end
Ctrl-W Delete the previous word
Alt-D Delete the next word
Ctrl-Y Paste the last thing deleted with U, K or W
Ctrl-_ Undo the last change
Ctrl-L Clear the screen without losing the line you were writing
Ctrl-X Ctrl-E Open the current line in your editor ($EDITOR)

The three that really change your life:

  • Ctrl-W + Ctrl-Y work as cut and paste: you delete a long path, type something else and bring it back wherever you want.
  • Ctrl-U is the correct way to abort a half-written line without losing the prompt, and it also serves to avoid running by mistake a dangerous command you have already typed.
  • Ctrl-X Ctrl-E is the emergency exit when the pipeline you are composing no longer fits on one line: it opens in vim or nano, you edit it comfortably and when you save and quit, Bash runs it.

  1. Tab completion

Tab completes what you are typing. If there is a single possibility, it completes it entirely; if there are several, it completes the common part and waits.

cd /srv/vel<Tab>              → cd /srv/veloz/
cat /var/log/veloz/ac<Tab>    → cat /var/log/veloz/access.log

Double Tab shows all the possible options when there is ambiguity. Pressing Tab twice on ls .../shipments-2026-08-0, Bash lists the three matches (shipments-2026-08-01.csv, -02 and -03) and leaves your line intact so you can keep typing.

Completion is not limited to paths: at the start of the line it completes command names (including those in ~/veloz-ops/bin, thanks to it being in the PATH since 01-02), and it also completes variables ($HIST<Tab>) and users (~jo<Tab>).

By installing the bash-completion package the system learns to complete options and arguments for each program: git che<Tab> proposes checkout, systemctl restart vel<Tab> proposes the services that exist.

sudo apt install bash-completion    # on Ubuntu 24.04 it usually comes preinstalled

Always use Tab, even when you know how to type the path: besides being faster, it is a verification. If Tab does not complete, that path does not exist, and you have just caught a typo before running an rm.

  1. Job control: first contact

When a command takes too long or you want your prompt back without killing it, job control comes into play:

Action Effect
Ctrl-C Interrupts the foreground process (sends it the SIGINT signal)
Ctrl-Z Suspends the process and gives you the prompt back
jobs Lists the session's jobs and their status
fg %1 Brings job 1 to the foreground
bg %1 Resumes it in the background
command & Launches the command directly in the background
tail -f /var/log/veloz/app.log
# you press Ctrl-Z  →  [1]+  Stopped     tail -f /var/log/veloz/app.log
bg %1     # keeps watching the log, but gives you the prompt back
jobs      # [1]+  Running     tail -f /var/log/veloz/app.log &
fg %1     # bring it back so you can stop it with Ctrl-C

The essential distinction is that Ctrl-C terminates the process and Ctrl-Z only pauses it: a suspended job still exists and consumes memory, and if you simply close the terminal it may be left half interrupted. Signals, orphan processes, nohup and serious process management are studied in 05-02.

  1. Aliases for the Veloz Envíos day-to-day

An alias is a short name for a long command. Defined in ~/.bashrc, they are available in every session:

# --- Navigation, listings and safety net (lesson 02-01) ---
alias ll='ls -lh --color=auto'
alias la='ls -lha --color=auto'
alias ..='cd ..'
alias rm='rm -i'
alias cp='cp -i'
alias mv='mv -i'

# --- Veloz Envíos ---
alias vlogs='cd /var/log/veloz'
alias vdata='cd /srv/veloz/data'
alias vops='cd ~/veloz-ops'
alias applog='tail -f /var/log/veloz/app.log'
alias errors='grep -c ERROR /var/log/veloz/app.log'
alias cities='cut -d, -f3 /srv/veloz/data/shipments.csv | tail -n +2 | sort | uniq -c | sort -rn'

After editing ~/.bashrc, remember to reload it with source ~/.bashrc (01-02). Check what is behind an alias with type cities, and run the original version by prefixing a backslash: \rm file ignores the rm -i alias.

Two limits worth knowing right away: aliases do not accept arguments in the middle (that is what functions are for, in 04-02) and they do not exist inside scripts, which is exactly why the next module starts where it starts. An alias is a personal shortcut; a script is a tool that can be shared, versioned and scheduled.

Common Mistakes and Tips

  • Retyping a long command by hand. If you ever typed it, it is in the history: Ctrl-R and three letters.
  • Leaving credentials in ~/.bash_history. Use the leading space with ignorespace, delete the entry with history -d and, better still, keep secrets in a file with 600 permissions.
  • Losing the history when closing several terminals. Add shopt -s histappend and PROMPT_COMMAND='history -a'.
  • Ctrl-S freezing the terminal. It is flow control; Ctrl-Q releases it and stty -ixon disables it permanently.
  • Using !! without looking. With destructive commands, check first with !!:p.
  • Confusing Ctrl-C with Ctrl-Z. The first terminates, the second suspends; suspended jobs are still there.
  • Depending on defensive aliases like rm -i. They do not exist in scripts or on other machines. They are a convenience, not a security policy.

Exercises

Exercise 1 — Working without retyping. Starting from ls -l /srv/veloz/data/archive/2026/08/shipments-2026-08-03.csv, achieve with the fewest keystrokes: (a) see the first three lines of that same file; (b) repeat the ls as root; (c) repeat the ls changing 08 for 07 in the first occurrence.

Exercise 2 — A professional history. Write the block you would add to ~/.bashrc so that the history keeps 10000 commands in memory and 20000 in the file, does not record duplicates or commands starting with a space, ignores ls, cd, pwd and history, shows date and time, and is not lost when working with several terminals. Explain each line.

Exercise 3 — Fast diagnosis. veloz-api is running slow and you want, in the same terminal, to watch the log live and at the same time check how many issues there are in the CSV. Describe the sequence of keys and commands, and explain why Ctrl-Z is preferable to Ctrl-C in this scenario.

Solutions

Solution to Exercise 1

head -3 !$      # (a) !$ inserts the last argument of the previous command
sudo !!         # (b) !! inserts the whole previous command
^08^07          # (c) repeats the previous one changing the FIRST occurrence of 08

Watch out with (c): ^08^07 replaces only the first match. In the path .../2026/08/shipments-2026-08-03.csv the first occurrence of 08 is the directory, so the result would be .../2026/07/shipments-2026-08-03.csv, which probably does not exist. To change every occurrence you need the global modifier: !!:gs/08/07/. It is a good reminder that history expansions are literal and it pays to check them with :p before running something important.

Solution to Exercise 2

HISTSIZE=10000                          # commands in memory during the session
HISTFILESIZE=20000                      # commands kept in ~/.bash_history
HISTCONTROL=ignoreboth                  # ignoredups + ignorespace
HISTIGNORE="ls:ll:cd:pwd:history:exit"  # noise that adds nothing to the history
HISTTIMEFORMAT="%F %T  "                # date and time on each history entry
shopt -s histappend                     # append to the file, do not overwrite it
PROMPT_COMMAND='history -a'             # flush after each command, not on close

ignoreboth is the double piece: ignoredups stops twenty consecutive ls commands from filling the history, and ignorespace enables the leading-space trick for commands with credentials. histappend and PROMPT_COMMAND go together and solve the classic simultaneous-sessions problem: without them, the last terminal to close overwrites the file with its history and wipes out everyone else's.

Solution to Exercise 3

tail -f /var/log/veloz/app.log     # 1. watch the log live
# Ctrl-Z                           → suspends and gives the prompt back
bg %1                              # 2. resume it in the background
grep -c ',issue,' /srv/veloz/data/shipments.csv     # 3. query while it keeps running
jobs                               # 4. check the job's status
fg %1                              # 5. bring it back and stop it with Ctrl-C when the time comes

Why Ctrl-Z and not Ctrl-C: Ctrl-C would kill the tail -f, and with it you would lose the continuity of the watch; the lines written while you were not looking would not appear when you relaunched it, because tail -f starts from the file's current end. Ctrl-Z followed by bg keeps the process alive and following the log without interruptions, while you get the prompt back to run the query. The only drawback is that in the background its lines get mixed into your session; in practice, for long watches a second terminal or tmux is preferred, and for processes that must survive the session closing, nohup (05-02).

Conclusion

With this lesson you close Module 2 and, with it, your command-line competence. You know how to reuse the history with !!, !$ and ^old^new, and above all how to search it with Ctrl-R, the shortcut that will save you the most time in your whole career. You have a history configured like a professional's: large, timestamped, free of noise, free of duplicates, safe from simultaneous sessions and —most importantly— free of credentials. You edit the line with readline instead of with the arrows, you use tab completion as a verification as well as a shortcut, you tell suspending a process apart from terminating it, and you have aliases that turn the most repeated Veloz Envíos queries into a single word.

Take stock of the whole module: you create and organize files with judgment; you interrogate app.log, access.log and shipments.csv with grep, cut, sort and uniq; you understand and adjust permissions; you compose filters with redirections and pipes that already write reports into ~/veloz-ops/logs; you select files with wildcards without fear; and you move fast. Everything you needed from the terminal is here.

And that is precisely why the limit arrives. An alias does not accept arguments, a five-filter pipeline cannot be documented or versioned, and nothing you have written today will run tomorrow at seven in the morning without you sitting there. In Module 3 we make the jump: you will save those lines into a file, learn to run it, to give it variables, conditions and arguments, and that chain you type every morning will become the first real command in ~/veloz-ops/bin. Scripting begins.

Bash Programming Course

Module 1: Introduction to Bash

Module 2: Basic Bash Commands

Module 3: Scripting Fundamentals

Module 4: Intermediate Scripting

Module 5: Advanced Scripting Techniques

Module 6: Working with External Tools

Module 7: Automation and Scheduling

Module 8: Best Practices and Optimization

Module 9: Real-World Projects

© Copyright 2026. All rights reserved