ITNEXT

ITNEXT is a platform for IT developers & software engineers to share knowledge, connect…

Follow publication

The Zsh Shell Tricks I Wish I’d Known Earlier

Boost Terminal Productivity

Piotr
ITNEXT
Published in
12 min readJul 14, 2024

Introduction

Navigating the command line efficiently can significantly enhance your productivity, especially when using powerful shells like Zsh. Whether you’re a seasoned developer or a curious newbie, mastering Zsh’s features can transform your workflow. In this guide, I’ll show you some essential Zsh tips and tricks, from cursor navigation to custom commands, that will streamline your terminal experience. Those are in no particular order, however I tried to group them into logical units. Each chapter shows different practical applications.

Why Zsh?

Zsh, or Z shell, is a Unix shell that can be used as an interactive login shell and as a command interpreter for shell scripting. Zsh is known for its rich feature set, which includes powerful command-line editing, built-in spell checking, and programmable command completion. It’s the default shell for macOS and is available on various GNU-Linux operating systems. It will also work on Windows with Windows Subsystem for Linux.

Who is This Blog For?

  • Developers: If you’re writing code, automating tasks, or managing servers, knowing Zsh can help you work more efficiently.
  • System Administrators: Zsh’s scripting capabilities and robust feature set can make managing systems and automating tasks easier.
  • DevOps Engineers: For those involved in continuous integration and deployment, mastering Zsh can streamline operations and enhance productivity.
  • Students and Beginners: If you’re new to the command line, learning Zsh can provide a solid foundation and make your learning curve smoother.
  • Tech Enthusiasts: If you love exploring new tools and optimizing your workflow, this guide will introduce you to some cool features of Zsh.

By the end of this blog, you’ll be equipped with practical tips and tricks to boost your command-line efficiency using Zsh.

Cursor Navigation and Line Editing

Efficient cursor movement and line editing are crucial for command-line productivity. Zsh provides powerful shortcuts to enhance these operations, making it easier to navigate and edit commands quickly.

Cursor Movement

Moving the cursor efficiently can save you a lot of time, especially when dealing with long commands.

  • Ctrl + A - Move the cursor to the beginning of the line.
  • Ctrl + E - Move the cursor to the end of the line.

These shortcuts allow you to quickly jump to the start or end of the command line, which is particularly useful when you need to edit the beginning or the end of a command.

Text Deletion

Deleting text efficiently helps you correct mistakes and modify commands without retyping them entirely.

  • Ctrl + U - Delete from the cursor to the start of the line.
  • Ctrl + K - Cut from the cursor to the end of the line.
  • Ctrl + W - Cut from the cursor to the start of the preceding word.
  • Alt + D - Remove from the cursor to the end of the next word.

These shortcuts enable you to quickly remove large chunks of text, whether it’s clearing the entire line or just deleting the last word you typed.

Text Manipulation

Manipulating text directly from the command line can enhance your efficiency, allowing you to make quick changes and corrections.

  • Ctrl + Y - Paste (yank) previously cut text.
  • Ctrl + Shift + _ - Undo the last keystroke in the command.
  • Ctrl + XT - Swap the current word with the previous word.
  • Ctrl + Q - Move the current command to the buffer, clear the line for a new command.

Using these shortcuts, you can easily move text around, undo mistakes, and restore previously deleted text, making your command-line experience much smoother.

Command Editing

Sometimes, you need more advanced editing capabilities to fine-tune your commands.

  • Ctrl + XE - Edit the current command in the default editor.

Globbing

Zsh provides advanced globbing features for flexible file matching, which is a powerful way to handle files and directories. Globbing allows you to specify patterns that match multiple filenames, enabling you to work with groups of files, directories and more very efficiently.

Standard Globbing

Standard globbing uses wildcards to match filenames based on simple patterns.

  • *.txt - Match all .txt files in the current directory.
  • file?.txt - Match files like file1.txt, file2.txt, etc., in the current directory.

These patterns help you quickly select and operate on groups of files without typing each filename individually.

Recursive Globbing

Recursive globbing extends the standard patterns to search through directories and subdirectories.

  • **/*.txt - Match all .txt files recursively within directories.

This powerful feature allows you to search for files across an entire directory tree, making it easy to find and manipulate files regardless of their location.

Extended Globbing

Zsh’s extended globbing features provide even more advanced pattern matching capabilities.

Enable extended globbing with the following command:

setopt EXTENDED_GLOB

Once enabled, you can use additional pattern matching features:

  • ls *(.) - List only regular files.
  • ls *(/) - List only directories.
  • ls *(-/) - List only directories and symbolic links to directories.

Extended globbing lets you refine your file searches with greater precision, making it easier to filter and list files based on specific criteria.

Examples of Globbing in Action

Here are some practical examples of using globbing to manage files:

  • mv *.txt backup/ - Move all .txt files to the backup directory.
  • rm **/*.log - Remove all .log files in the current directory and all subdirectories.
  • cp *.{jpg,png} images/ - Copy all .jpg and .png files to the images directory.

By leveraging the power of globbing, you can streamline your file management tasks, making it easier to work with large sets of files and directories.

Command History and Expansion

Zsh offers robust features for recalling and manipulating previous and current commands. These features allow you to efficiently reuse and modify commands, which can save a significant amount of time, especially when working with complex commands or long command sequences.

History Recall

Zsh provides several shortcuts to recall and reuse previous commands or their arguments:

  • Ctrl + r — Display commands history and navigate history buffer with Ctrl + P and Ctrl + N (privided no vim key mode is enabled)
  • Alt + . or <Esc> + . - Insert the last argument of the previous command (same as !$).
  • <Esc> + _ - Insert the last word of the previous command, cycles through arguments.
  • !! — repeat the full previous command, useful for sudo !! to append sudo to previous command
  • !:0 - Repeat the previous command without arguments.
  • !vi - Run the most recent command that started with ‘vi’.

These shortcuts enable quick retrieval of previously used commands, allowing you to modify and re-execute them without retyping the entire command.

History Modification

Modifying previously executed commands can help you correct mistakes or adjust commands for different tasks without starting from scratch:

  • !!:s/x/y - Substitute ‘x’ with ‘y’ in the previous command.
  • ^foo^bar - Replace ‘foo’ with ‘bar’ in the previous command and execute it.

These history modification shortcuts are particularly useful for fixing typos or changing parameters in commands you’ve just executed.

Current Command Expansion

You can also expand arguments of the current command line, making it easier to reuse parts of commands:

  • !#^ - Expand the first argument of the current command.
  • !#$ - Expand the last argument of the current command.

This is very useful for example when copying or renaming a file with long name:

  • cp reallylongnamefile backup-!#$ would expand to the file name after hitting TAB

Quick Fixes

Zsh includes several shortcuts for quickly fixing and re-executing commands:

  • fc - Fix command: opens the last command in the editor.
  • r - Repeat the last command (can be combined with substitution, e.g., r foo=bar).

Using these shortcuts, you can open previous commands in your default text editor for quick corrections, or simply re-execute commands with minor modifications.

Examples of Command History and Expansion in Action

Here are some practical examples demonstrating the use of history and expansion features:

  • !!:s/foo/bar - Re-execute the previous command, replacing ‘foo’ with ‘bar’.
  • ^error^success - Correct ‘error’ to ‘success’ in the last executed command and run it again.
  • echo "Hello, World!" !:0 - Repeat the last command without arguments.
  • sudo !! - Re-execute the previous command with sudo.

Parameter Expansion and Shell Variables

Zsh provides powerful features for working with parameters and shell variables, making it easier to manage data and automate tasks in your shell environment.

Positional Parameters

Positional parameters are variables that are assigned values from the arguments passed to a script or function.

  • $# - Number of positional parameters passed to the script or function.
  • $@ - All positional parameters, individually quoted.
  • $* - All positional parameters as a single, space-separated string.

These parameters allow you to access and manipulate the arguments passed to your scripts and functions, making your scripts more flexible and powerful.

Special Variables

Special variables provide information about the current state of the shell or the last executed command.

  • $? - Exit status of the last executed command.
  • $_ - Last argument of the previous command.

There are many more special variables you can read about in the zsh documentaion

Parameter Expansion

Parameter expansion allows you to manipulate the values of variables in various ways.

Basic Expansion:

  • ${var} - Expands to the value of var.

Default Values:

  • ${var:-default} - Use default if var is unset or null.
  • ${var:=default} - Assign default to var if var is unset or null.

String Manipulation:

  • ${var#pattern} - Remove the shortest match of pattern from the beginning of var.
  • ${var##pattern} - Remove the longest match of pattern from the beginning of var.
  • ${var%pattern} - Remove the shortest match of pattern from the end of var.
  • ${var%%pattern} - Remove the longest match of pattern from the end of var.

Substring Extraction:

  • ${var:offset} - Extract substring from var starting at offset.
  • ${var:offset:length} - Extract length characters of substring from var starting at offset.

These expansions provide powerful tools for manipulating strings and variables within your shell scripts and commands.

Examples of Parameter Expansion and Shell Variables in Action

Here are some practical examples demonstrating the use of parameter expansion and shell variables:

  • ${filename%.txt}.md - Change the extension of filename from .txt to .md.
  • ${var:-default} - Use default if var is unset or null.
  • ${var:1:3} - Extract three characters from var, starting at the second character.

Using Shell Variables in Scripts

You can use these features to create more robust and flexible scripts. For example:

#!/bin/zsh
greet() {
local name=${1:-User}
echo "Hello, $name!"
}
greet "Alice"
greet

In this script, the greet function uses a positional parameter with a default value, ensuring it always has a value to work with.

Path and Filename Operations

Zsh provides various shortcuts and techniques for working with file paths and filenames, simplifying the process of managing files and directories.

Path Expansion

Path expansion helps you quickly navigate and manipulate file paths.

  • /u/lo/b<Tab> - Quick path expansion (e.g., expands to /usr/local/bin).

This feature allows you to type partial paths and use the Tab key for auto-completion, saving time and reducing typing errors.

Filename Manipulation

Zsh offers several parameter expansions to manipulate filenames, which can be very useful in scripts and command-line operations.

Remove Extension:

  • ${file:r} - Remove the extension from a filename variable.

Get Extension:

  • ${file:e} - Get just the extension from a filename variable.

Convert to Uppercase:

  • ${file:u} - Convert a filename variable to uppercase.

Convert to Lowercase:

  • ${file:l} - Convert a filename variable to lowercase.

These expansions allow you to extract or modify specific parts of filenames without the need for external tools or complex commands.

Examples of Path and Filename Operations in Action

Here are some practical examples of using Zsh’s path and filename manipulation features:

  • file="example.txt" - Define a filename variable.
  • echo ${file:r} - Output: example (removes the .txt extension).
  • echo ${file:e} - Output: txt (gets the extension).
  • echo ${file:u} - Output: EXAMPLE.TXT (converts to uppercase).
  • echo ${file:l} - Output: example.txt (converts to lowercase).

Real-World Usage in Scripts

Using these features in scripts can make file manipulation tasks easier and more efficient. For example:

#!/bin/zsh
process_files() {
for file in *.txt; do
local base_name=${file:r}
local new_name="${base_name}.md"
mv "$file" "$new_name"
echo "Renamed $file to $new_name"
done
}
process_files

In this script, the process_files function renames all .txt files in the current directory to .md files, using the filename manipulation features of Zsh.

Quick Path Expansion

Zsh also supports quick path expansion, making directory navigation more efficient:

cd /u/lo/b<Tab>  # Expands to /usr/local/bin

Brace and Range Expansions

Zsh offers powerful features for generating sequences and sets of items using brace and range expansions. These features are incredibly useful for creating lists, directories, or files in a systematic and efficient manner.

Brace Expansion

Brace expansion allows you to generate arbitrary strings by specifying patterns within braces {}. This is particularly useful for creating multiple items with similar names.

Examples:

  • echo {apple,banana,cherry} - Expands to apple banana cherry.
  • mkdir -p project/{src,bin,lib} - Creates project/src, project/bin, and project/lib directories.

Using brace expansion, you can quickly generate sets of strings or directories without typing each one individually.

Range Expansion

Range expansion generates sequences of numbers or letters, which can be very handy for creating ordered lists.

Numeric Range:

  • echo {1..5} - Expands to 1 2 3 4 5.
  • echo {001..005} - Expands to 001 002 003 004 005.

Alphabetic Range:

  • echo {a..e} - Expands to a b c d e.
  • echo {A..E} - Expands to A B C D E.

Range expansion simplifies the process of generating sequences, especially when dealing with large ranges or complex patterns.

Combining Brace and Range Expansions

You can combine brace and range expansions to create more complex patterns.

Examples:

  • echo file{1..3}.{txt,md} - Expands to file1.txt file1.md file2.txt file2.md file3.txt file3.md.
  • mkdir project{A..C}/{src,bin,lib} - Creates directories like projectA/src, projectA/bin, projectA/lib, and so on for projectB and projectC.

This combination provides a powerful way to generate complex sets of items with minimal effort.

Practical Applications

Here are some practical examples demonstrating the use of brace and range expansions:

Creating Multiple Files

touch {chapter1,chapter2,chapter3}.md

Generating Sequences in Scripts

for i in {1..10}; do
echo "Item $i"
done

Batch Renaming Files

for file in img{001..005}.jpg; do
mv "$file" "${file%.jpg}.png"
done

Creating a Series of Directories

mkdir -p project/{module1,module2}/{src,bin,doc}

Generating HTML Files

touch {index,about,contact}.html

Creating Numbered Files with Leading Zeros

touch file{001..010}.txt

Directory Navigation Techniques

Efficient directory navigation is crucial for command-line productivity. Zsh provides several shortcuts and features to streamline moving between directories. Directory Shortcuts

Zsh includes handy shortcuts to quickly navigate through your directory structure.

cd - - Switch to the previous directory you were in. This is useful when you need to toggle between two directories frequently.
cd ~ - Change to your home directory. It's a quick way to return to your home base from anywhere in the filesystem.
cd / - Change to the root directory. This is useful for accessing the top level of the filesystem.
cd .. - Move up one directory level. This is helpful for backtracking through the directory tree.
cd ../.. - Move up two directory levels. You can chain more .. to go further up the directory structure.
cd - - Toggle back to the previous directory you were in.
cd -<Tab> - Toggle list of directories you have visited.

Custom Commands and Key Bindings

Zsh allows for the creation of custom commands and key bindings to further enhance your workflow. These features enable you to tailor the shell to your specific needs, making it more efficient and personalized.

Understanding BUFFER and zle

  • BUFFER represents the current command line content. You can manipulate it to change the text on your command line.
  • zle (Zsh Line Editor) is used to manipulate the command line. It allows you to create custom widgets and key bindings.

Creating Custom Commands

Creating custom commands in Zsh can simplify repetitive tasks and improve your efficiency.

For example, you can create a function to copy the entire command line to the clipboard:

copy_line_to_clipboard() {
echo -n $BUFFER | xclip -selection clipboard
}
zle -N copy_line_to_clipboard

This function uses xclip to copy the content of BUFFER (the current command line) to the clipboard.

Adding Custom Key Bindings

You can bind custom functions or existing ZLE commands to specific key sequences to streamline your workflow.

  • bindkey '^Y' copy_line_to_clipboard - Binds the Ctrl+Y shortcut to the copy_line_to_clipboard function.
  • bindkey '^@' autosuggest-accept - Binds the Ctrl+Space shortcut to accept autosuggestions.
  • bindkey '^X^T' transpose-words - Binds Ctrl+X followed by Ctrl+T to transpose words.

These key bindings allow you to quickly access your custom commands and other useful functions directly from the keyboard.

Examples of Custom Commands and Key Bindings

Here are some practical examples of custom commands and key bindings:

Open the current command in the default editor:

edit_command_in_editor() {
BUFFER="vim $(fc -ln -1)"
zle accept-line
}
zle -N edit_command_in_editor
bindkey '^Xe' edit_command_in_editor

Quickly clear the screen and display the current directory:

clear_and_display_dir() {
clear
echo "Current Directory: $(pwd)"
}
bindkey '^L' clear_and_display_dir

Using Custom Commands in Scripts

Custom commands can also be used within scripts to enhance their functionality and maintainability.

#!/bin/zsh
# Custom function to backup files
backup_files() {
local backup_dir="/backup/$(date +%Y%m%d)"
mkdir -p "$backup_dir"
cp -r ~/Documents/* "$backup_dir"
echo "Backup completed at $backup_dir"
}
# Custom key binding to invoke backup function
zle -N backup_files
bindkey '^B' backup_files
# Execute backup function if this script is run directly
if [[ "${(%):-%N}" == "${(%):-%x}" ]]; then
backup_files
fi

In this script, the backup_files function creates a backup of the Documents directory. The function is bound to Ctrl+B for quick access, and the script also runs the function directly if executed.

Check out more key bindings and configuraiton ideas in my .zshrc config.

Closing Thoughts

Mastering Zsh can transform your command-line experience from a complicated, error prone tasks into a streamlined, efficient workflow. By leveraging its powerful features, from cursor navigation and line editing to custom commands and key bindings, you can significantly enhance your productivity. There is of course learning curve but it’s well worth it in the long run.

Zsh is not just a shell, it’s also a scripting languag and a gateway to a more productive and efficient way of working with the command line. Whether you’re a developer, system administrator, DevOps engineer, or just someone who loves tinkering with technology, mastering Zsh will empower you to do more with less effort.

Thanks for taking the time to read this post. I hope you found it interesting and informative.

🔗 Connect with me on LinkedIn

🌐 Visit my Website

📺 Subscribe to my YouTube Channel

Sign up to discover human stories that deepen your understanding of the world.

Published in ITNEXT

ITNEXT is a platform for IT developers & software engineers to share knowledge, connect, collaborate, learn and experience next-gen technologies.

Written by Piotr

My mission is to share enthusiasm and appreciation for digital technology. I want to inspire you to try tools, create and use software and learn new things.

Responses (12)

Write a response