Skip to content

필사 모드: Modern Bash & Shell Scripting 2026 Complete Guide - Bash 5.2 · Zsh 5.9 · fish 4 · Nushell · Murex · ShellCheck · Bashly · just Deep Dive

English
0%
정확도 0%
💡 왼쪽 원문을 읽으면서 오른쪽에 따라 써보세요. Tab 키로 힌트를 받을 수 있습니다.
원문 렌더가 준비되기 전까지 텍스트 가이드로 표시합니다.

Prologue — Why talk about the shell again in 2026

June 1989. Brian Fox released the first version of the Bourne-Again SHell as part of the GNU Project. 37 years later, in May 2026, we still tap on the shell every day. Even in an age when AI writes our code, `cd`, `ls`, `grep`, `git`, `kubectl`, and `ssh` live on as muscle memory in our fingers.

But the landscape has clearly shifted.

- **Bash 5.2** (released September 2022) is still the GNU standard, and 5.3 is due to arrive within 2026. Chet Ramey has maintained it since the early 1990s.

- **Zsh 5.9** has been the macOS default since Catalina, and it commands a massive plugin ecosystem of Oh My Zsh, Prezto, and Antigen.

- **fish 4** was fully rewritten in Rust in 2024. Start-up time, syntax highlighting, and autosuggestion all got faster and lighter on memory.

- **Nushell 0.105+** shakes the very definition of a shell. Every command emits and consumes structured data (a table), and you write SQL-flavored pipelines like `ls | where size > 1mb | sort-by modified`.

- **Murex** — a shell with a type system. **xonsh** — a shell scripted in Python. **Elvish** — an expression-rich shell. All of them have carved out their own niche.

- And then the tooling. **ShellCheck** is the ESLint for shell scripts. **shfmt** is the formatter. **bashly** generates full-stack CLI apps from a YAML spec. **gum** lets shell scripts paint pretty TUIs. **fzf**, **ripgrep**, **fd**, **eza**, **dust**, **bottom**, **just**, **mise** — every one of them is a next-generation rewrite of GNU coreutils in Rust or Go.

- AI showed up too. **shell_gpt (sgpt)** turns natural language into shell commands, **Warp Terminal** floats AI suggestions, and **Amazon Q Developer** (formerly Fig) sharpens completion.

This article walks through those tools and patterns across 22 chapters. The shell itself (1–6), scripting best practices (7–12), modern CLI tools (13–17), build/task runners (18–19), AI and terminals (20), Korea/Japan ops culture (21), and finally the future (22).

> The shell isn't going away. It's just that the shell is no longer merely an input line. We've moved from the era of "shell vs IDE" to the era of "structured shell + modern tools + AI."

Chapter 1 · Bash 5.2 — the standard, from Brian Fox to Chet Ramey

Bash is the GNU project's reference shell. Brian Fox wrote the first version in 1989, and since 1992 Chet Ramey (at Case Western Reserve University) has been almost the sole maintainer. As of May 2026 the stable version is **5.2.37** (patch release November 2025), with 5.3 announced for later in the year.

**What landed in Bash 5.2**

- `BASH_REMATCH` is more reliable across regex matches.

- The `globskipdots` shell option drops `.` and `..` from `*` expansion, killing a long-running gotcha.

- `varredir_close` closes file descriptors safely when process substitution ends.

- `${var@k}` is a new parameter transformation that pulls out keys.

- `wait -p VAR` stores the resulting PID into a variable.

- Function tracing improvements make `set -T`/`trap ... DEBUG` more accurate.

**What's coming in Bash 5.3**

- `BASH_TRAPSIG` exposes which signal the trap handled.

- A curses-like mode is under discussion.

- Additional POSIX compatibility hardening.

**Why are we still using Bash?**

Three answers. 1) **Ubiquity** — Linux, macOS, WSL, BusyBox, Docker's `alpine`, almost everywhere. 2) **CI/CD baseline** — GitHub Actions, GitLab CI, Jenkins all default to bash. 3) **40 years of material** — `man bash`, Stack Overflow, the ABS Guide — the cumulative knowledge dwarfs every alternative.

Bash 5.2 features in action

shopt -s globskipdots # * no longer matches . or ..

echo *

wait -p captures the background PID

sleep 5 &

wait -p PID $!

echo "the last background PID was $PID"

New parameter transformation

declare -A map=([a]=1 [b]=2)

echo "${map[@]@k}" # list keys

**The macOS trap — Bash 3.2.57**

Here lies a major trap. The `/bin/bash` on macOS is **Bash 3.2.57, frozen since 2007** because Apple refuses GPLv3. Anything 4.0+ (`declare -A`, `mapfile`, `readarray`, `${var,,}` lowercasing, `**` globstar) doesn't work. The fix: `brew install bash` to get 5.2, and **never use `#!/bin/bash`** — that grabs the 3.2 one. Use `#!/usr/bin/env bash`.

Chapter 2 · Zsh 5.9 — the macOS default, home of Oh My Zsh

Paul Falstad (Princeton) kicked off Zsh in 1990. The current stable in May 2026 is 5.9, with 5.10 imminent. Since Apple switched the macOS Catalina default shell from Bash 3.2 to Zsh 5.7 in 2019, **more than half of developer laptops worldwide now run Zsh** (Stack Overflow Developer Survey 2025).

**What sets Zsh apart**

- **Global aliases** — `alias -g G='| grep'` lets you write `cat foo G bar` anywhere.

- **Extended globbing** — `**/*.go(.)` matches only regular files, `*(om[1,10])` the 10 most recent.

- **Associative arrays** are built in (Bash needs 4.0+).

- **Multi-fanout redirection** — `cmd > >(tee a) > >(tee b)`.

- **Rich prompt system** — `PROMPT_SUBST` for dynamic prompts.

- **An overwhelming completion system** — `compinit` knows nearly every command's options.

Zsh extended globbing

setopt EXTENDED_GLOB

ls **/*.log~*backup* # every .log except backups

ls *(om[1,10]) # ten most recent files

ls *(/^F) # empty directories only

**Oh My Zsh — the largest framework**

Robby Russell started it in 2009. As of 2026 it has 170k GitHub stars. 200+ themes, 300+ plugins. `git`, `kubectl`, `aws`, `docker`, `node`, `python` plugins flip on completion and aliases with one line.

~/.zshrc example

plugins=(git kubectl aws docker fzf z)

ZSH_THEME="agnoster"

source $ZSH/oh-my-zsh.sh

**Prezto / Zinit / Antidote — faster alternatives**

Oh My Zsh is rich but can slow start-up. Faster options:

- **Prezto** — Sorin Ionescu, 2012. Modular, lightweight.

- **Zinit** — turbo mode asynchronously loads plugins, start-up around 50 ms.

- **Antidote** — newer generation, plain-text plugin file.

Zinit turbo mode — async loading so the prompt isn't blocked

zinit wait lucid for \

OMZP::git \

OMZP::kubectl \

zsh-users/zsh-autosuggestions \

zdharma-continuum/fast-syntax-highlighting

**Zsh's downsides**

It is not 100% POSIX compatible. Some scripts behave differently from bash. So either annotate `#!/usr/bin/env zsh` explicitly or keep shared scripts in bash and use zsh only interactively — a common split.

Chapter 3 · fish 4 — the user-friendly shell, reborn in Rust

fish stands for "friendly interactive shell." Axel Liljencrantz launched it in 2005, and the 4.0 release in 2024 was a **complete rewrite from C++ to Rust**. May 2026 stable is 4.1, with start-up around 30–50 ms.

**fish's signature — sensible defaults out of the box**

- **Autosuggestion** — history-based suggestions are always on, displayed in gray and accepted with →.

- **Syntax highlighting** — red (broken command), green (valid), yellow (quoted) updates as you type.

- **Abbreviations** — stronger than aliases. They expand at input time, so history holds the real command.

- **Rich option completion** — it parses `man` pages to learn options.

- **Web-based config** — `fish_config` opens a browser theme picker.

fish syntax differs from bash. Variables, functions, and if are all clearer.

set -gx PATH $HOME/bin $PATH

function gco --description "git checkout"

git checkout $argv

end

Abbreviations: expand at input time

abbr -a gc git commit

abbr -a gst git status

**fish's downside — not POSIX**

fish is not POSIX compatible. `[ ]`, `&&`, `||` and other syntax differ. You cannot import `.zshrc` or `.bashrc` straight away. The usual compromise: keep shared scripts in bash, use fish for interactive shells.

**What the 4.0 Rust rewrite delivered**

- Start-up time roughly halved.

- Lower memory usage.

- The C++ memory-safety hazards went away.

- Lower barrier to entry for external contributors.

Chapter 4 · Nushell — structured-data pipelines

Nushell launched in 2019, started by Jonathan Turner and Yehuda Katz. It is written in Rust, and May 2026 stable is 0.105. The pitch is **"every command exchanges data (tables)"**, inspired by PowerShell but fused with Unix philosophy, so it stays lighter and faster.

**Signature — table-driven pipes**

Take a directory listing as a table, filter by size, sort, take 5

ls | where size > 1mb | sort-by modified | first 5

JSON parses automatically

http get https://api.github.com/repos/nushell/nushell | get stargazers_count

CSV → JSON in one line

open data.csv | to json | save data.json

**Why it matters**

In bash land you cobble together `awk`, `cut`, `jq`, `xargs` for text pipelines. Once parsing logic stacks up, readability dies. Nushell treats the table itself as a first-class object, so `where`, `sort-by`, `group-by`, `select`, `each` give you SQL-flavored expressions.

**Limitations**

- It does not run bash scripts as-is.

- External commands speak text, so you still convert with `from json` / `from csv`.

- Being 0.x, syntax shifts release to release — safer for interactive analysis than production scripting.

**Who is it for?**

- Data engineers — a delightful local shell for small data wrangling.

- Cloud operators — `kubectl get pods -o json | from json | where ...` is natural.

Chapter 5 · Murex · xonsh · Elvish — third-path shells

**Murex — a shell with a type system**

A British developer, Andrew Stewart, builds it. May 2026 sits in the 6.x line. Variables carry types and JSON/YAML/TOML are first-class. A compromise between Nushell and bash compatibility.

Declare a variable type

set: int counter = 0

set: string name = "world"

JSON handling is first-class

open my.json -> [name age] -> format json

**xonsh — a shell scripted in Python**

Anthony Scopatz started it in 2015. Mix Python and shell in one file. Beloved by data scientists.

.xonshrc — Python and shell interleaved

echo @(os.getcwd())

Shell output becomes a Python list

ls = $(ls -la).split('\n')

for line in ls:

print(line)

**Elvish — the expressive shell**

Qi Xiao (China) launched it in 2014, written in Go. Lambdas, closures, first-class functions live inside the shell. An early "structured shell" experiment that predated Nushell.

fn greet [name]{

echo "Hello, "$name

}

greet world

**What they have in common**

They trade POSIX compatibility for expressiveness. Using them for init scripts on production servers is risky, but as a personal laptop interactive shell or for data work they're attractive.

Chapter 6 · POSIX shell · dash · ksh · tcsh — legacy and minimalism

**POSIX shell** is the shell IEEE 1003.1 defines. All the shiny features of bash 4+ (`[[ ]]`, `(())`, `declare -A`, `<<<`) are off the table. In exchange, **it runs almost everywhere Unix runs**.

**dash** (Debian Almquist SHell) is the minimal POSIX shell Debian adopted as `/bin/sh`. On Ubuntu and Debian, `/bin/sh` is dash. It starts 4–10x faster than bash, which keeps init scripts snappy.

POSIX-compatible script template

#!/bin/sh

set -eu

No [[ ]], only [ ]

if [ "$1" = "build" ]; then

echo "building..."

fi

No arrays either — use positional parameters

set -- a b c

for x in "$@"; do echo "$x"; done

**ksh** (Korn Shell) was created by David Korn at Bell Labs in 1983. Once the standard on Solaris and AIX. **ksh93** is the last major release; the ksh93u+m fork from 2020 keeps it alive. You'll only run into it on legacy AIX/Solaris systems.

**tcsh** is the C shell's descendant. Some BSDs used it as the default. Common in 1990s university Unix labs. By 2026 it is nearly unused — FreeBSD keeping it as root's default is about it.

**When to use what**

- **Production init/cron scripts** → POSIX `/bin/sh` (dash/ash). Fast and dependable.

- **Developer laptop general scripts** → bash 5.2. Rich features, sea of documentation.

- **Interactive daily shell** → zsh or fish.

- **AIX/Solaris legacy** → ksh.

Chapter 7 · Shell scripting strict mode — set -euo pipefail

Every script that opens with `#!/usr/bin/env bash` should put `set -euo pipefail` on the second line.

#!/usr/bin/env bash

set -euo pipefail

IFS=$'\n\t'

**What each option prevents**

- `set -e` (`errexit`) — exits immediately if a command returns non-zero. **Does not apply inside `if`/`while`/`||`** (deliberate exception).

- `set -u` (`nounset`) — undefined variables become errors, blocking silent typo failures.

- `set -o pipefail` — if any command in a pipeline fails, the whole pipeline fails. Default behavior only inspects the last command's exit code.

- `IFS=$'\n\t'` — restricts word splitting to newline/tab, safer for filenames with spaces.

**The trap with `set -e`**

`set -e` is not absolute. It does nothing inside `cmd | other`, `cmd || true`, `if cmd; then ...`. So you need `pipefail` paired with it. `set -e` also interacts oddly with traps inside functions — **when traps are involved, explicit `if` checks are safer**.

**Comparison — a well-formed script header**

#!/usr/bin/env bash

vim: set ft=bash ts=2 sw=2 :

set -Eeuo pipefail # -E propagates ERR traps into functions

IFS=$'\n\t'

Debug mode: BASH_X=1 ./run.sh

if [[ "${BASH_X:-0}" == 1 ]]; then

set -x

fi

readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

readonly TMP_DIR="$(mktemp -d)"

trap 'rm -rf "$TMP_DIR"' EXIT

Chapter 8 · trap and mktemp — never forget cleanup

If a script creates temporary files, **you must clean them up**. A bare `rm` skips error paths. Use `trap`.

TMP=$(mktemp -d -t myapp.XXXXXX)

trap 'rm -rf "$TMP"' EXIT

More elaborate: split by signal

cleanup() {

local exit_code=$?

rm -rf "$TMP"

if [[ $exit_code -ne 0 ]]; then

echo "script terminated abnormally (code=$exit_code)" >&2

fi

exit $exit_code

}

trap cleanup EXIT

trap 'echo "got INT"; exit 130' INT

trap 'echo "got TERM"; exit 143' TERM

**`mktemp` best practices**

- Always create a directory with `-d` and place files inside — cleanup becomes one line.

- Pass `-t prefix.XXXXXX` for easier debugging.

- macOS `mktemp` flags differ from GNU. For cross-platform stick to the short form `mktemp -d "tmp.XXXXXX"`.

**Why not just use `/tmp/myscript`**

Three reasons. 1) **TOCTOU attack** — someone pre-creating the same name to bypass permissions. 2) **Collisions** — two concurrent runs collide. 3) **Cannot clean up safely** — deleting another instance's files is dangerous.

Chapter 9 · Argument parsing — getopts and beyond

**Start with `getopts`**

It's a bash builtin, no external dependencies. Only single-character options, but that covers 99% of cases.

usage() {

cat <<'USAGE'

Usage: deploy.sh [-e env] [-n name] [-d]

-e env deployment environment (dev/staging/prod, required)

-n name service name (default: $(basename $PWD))

-d dry-run mode

-h this help

USAGE

}

DRY_RUN=0

NAME="$(basename "$PWD")"

while getopts ":e:n:dh" opt; do

case $opt in

e) ENV="$OPTARG" ;;

n) NAME="$OPTARG" ;;

d) DRY_RUN=1 ;;

h) usage; exit 0 ;;

\?) echo "unknown option: -$OPTARG" >&2; usage; exit 2 ;;

:) echo "option -$OPTARG needs an argument" >&2; usage; exit 2 ;;

esac

done

shift $((OPTIND - 1))

: "${ENV:?ENV is required (-e)}"

**For long options — roll your own**

Handle long options like --help, --env=dev manually

while [[ $# -gt 0 ]]; do

case $1 in

--env=*) ENV="${1#*=}"; shift ;;

--env) ENV="$2"; shift 2 ;;

--help|-h) usage; exit 0 ;;

--) shift; break ;;

-*) echo "unknown option: $1" >&2; exit 2 ;;

*) ARGS+=("$1"); shift ;;

esac

done

**Alternatives — bashly / docopt.sh**

For complex CLIs, generate code with bashly (chapter 12) or auto-build a parser from your help text with docopt.sh.

Chapter 10 · Arrays and associative arrays — the core of bash 4+

**Indexed arrays**

arr=("a" "b" "c")

echo "${arr[0]}" # a

echo "${arr[@]}" # every element

echo "${#arr[@]}" # element count

arr+=("d") # append

unset 'arr[1]' # drop index 1 (mind sparse arrays after this)

**Associative arrays** — bash 4.0+, standard in zsh, **broken on macOS bash 3.2**

declare -A users

users[alice]=admin

users[bob]=guest

users[carol]=admin

for u in "${!users[@]}"; do

echo "$u: ${users[$u]}"

done

Key existence check

[[ -v users[alice] ]] && echo "alice exists"

**Passing arrays to functions — bash's eternal trap**

Wrong — the array flattens into one argument

print_arr() { for x in "$@"; do echo "$x"; done; }

arr=(a "b c" d)

print_arr "${arr[@]}" # Correct — quoted + @ expansion passes element-by-element

Safer — nameref (bash 4.3+)

print_by_ref() {

local -n ref=$1

for x in "${ref[@]}"; do echo "$x"; done

}

print_by_ref arr

Chapter 11 · Functions, local, readonly, process substitution

**Function guidelines**

Functions always use local. Otherwise globals leak.

greet() {

local name=$1

local greeting=${2:-"Hello"}

echo "$greeting, $name!"

}

Return values go to stdout; exit codes are 0 / non-zero

add() {

local a=$1 b=$2

echo $((a + b))

}

sum=$(add 3 4)

**`readonly` for constants**

readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

readonly TIMEOUT_SECONDS=30

readonly -a ENVS=(dev staging prod)

**Process substitution — `<()` and `>()`**

A trick for what pipes cannot express. Avoids temporary files by feeding file descriptors directly.

diff between two commands

diff <(sort file1) <(sort file2)

Tee one output into multiple downstream commands

program | tee >(grep ERROR > err.log) >(grep WARN > warn.log) > full.log

Pass content through an fd to a command that expects a file

psql -f <(echo "SELECT * FROM users WHERE id=$ID")

Chapter 12 · ShellCheck · shfmt · bashly — the modern shell workflow

**ShellCheck — the ESLint for shell**

Vidar Holen (Norway) launched it in 2012. Written in Haskell. May 2026 sits around 0.10. The standard practice: run ShellCheck on every PR.

In CI

shellcheck script.sh

Frequent findings

SC2086: $var is unquoted — word-splitting hazard

SC2046: $(...) result is unquoted

SC2155: declare/local combined with command substitution loses the exit code

SC2034: variable declared but never used

**shfmt — the shell formatter**

Daniel Martí (mvdan) maintains this Go tool. It sits next to shellcheck. `gofmt`-style consistent indentation and ordering for shell scripts.

Indent two spaces, indent case patterns, handle stdin redirection

shfmt -i 2 -ci -sr -d script.sh

pre-commit hook example

shfmt -l -w . # auto-format every .sh file

**bashly — full-stack CLI in bash**

Built by Danny Ben Shitrit. Define the command tree in YAML and bashly emits a complete bash CLI — argument parsing, help, version, completion.

src/bashly.yml

name: mycli

help: my CLI tool

version: 1.0.0

commands:

- name: deploy

help: deploy to an environment

args:

- name: env

required: true

allowed: [dev, staging, prod]

flags:

- long: --dry-run

short: -d

help: dry-run mode

bashly generate

./mycli deploy prod --dry-run

Chapter 13 · fzf · ripgrep · fd · bat · eza — modern Unix tools

**fzf — the fuzzy finder**

Junegunn Choi (Korea, Kakao) started it in 2013. Written in Go. May 2026 sits around 0.55. One of the most influential open-source projects ever shipped by a Korean developer.

fzf basics

ls | fzf

history | fzf

git log --oneline | fzf | awk '{print $1}' | xargs git show

Key bindings (Ctrl+R for history, Ctrl+T for files, Alt+C for directories)

source /usr/share/fzf/key-bindings.bash

**ripgrep (rg) — fast grep**

Andrew Gallant (BurntSushi) built it. Written in Rust. 5–10x faster than grep, and it respects `.gitignore` by default.

Basic usage

rg "TODO" --type rust

rg -i "error" -C 2 # case-insensitive, 2 lines of context

rg --files-with-matches "Apache"

**fd — find replacement**

David Peter (sharkdp) ships this Rust tool. More intuitive than find and faster.

fd "\.rs$" # every Rust file

fd -e py -t f # Python files only

fd -H "node_modules" # include hidden

**bat — cat with syntax**

Also by sharkdp. cat plus syntax highlighting and git diff display.

bat README.md

bat -p src/main.rs # plain mode, syntax only

**eza — successor to exa, ls replacement**

A fork of exa maintained by ogham. Actively maintained since 2024.

eza -l --git --icons

eza --tree --level 2

**Why use all of this?**

GNU coreutils ship a 50-year-old interface. Options aren't intuitive, output lacks color, `.gitignore` is invisible. These tools provide **sensible defaults of the 2010s and beyond** — colorized output, indexing, ignore-file awareness, JSON output.

Chapter 14 · System monitoring — bottom · btop · htop · glances

**htop** — Hisham Muhammad's late-1990s classic. Color + mouse + tree view. Still the most widely installed.

**btop** — Aristocratos's C++ successor. Richer visuals, GPU/disk/network graphs, mouse navigation.

**bottom (btm)** — ClementTsang's Rust implementation. Cross-platform with JSON-style config.

**glances** — Nicolas Hennion's Python project. Has a web API / Prometheus exporter for monitoring integration.

**Comparison**

| Tool | Language | Strength | System overhead |

| --- | --- | --- | --- |

| htop | C | classic, stable | lowest |

| btop | C++ | flashy, GPU | medium |

| bottom | Rust | cross-platform, config rich | medium |

| glances | Python | web API, exporter | a bit higher |

bottom config sample (~/.config/bottom/bottom.toml)

[flags]

hide_avg_cpu = false

mem_as_value = true

network_use_binary_prefix = true

Chapter 15 · jq · yq · dasel · gron — structured data processing

**jq — the JSON standard**

Stephen Dolan started it in 2012. A functional JSON query language. Available everywhere.

curl -s api.github.com/users/torvalds | jq '.public_repos'

kubectl get pods -o json | jq '.items[] | .metadata.name'

cat data.json | jq -r '.users[] | select(.age > 30) | .name'

**yq — jq for YAML**

Mike Farah's Go implementation (mikefarah/yq) is the standard. Inherits jq syntax almost verbatim.

yq '.spec.replicas = 3' deployment.yaml

yq '.services | keys' docker-compose.yml

**dasel — cross-format**

Treats JSON, YAML, TOML, XML, CSV with the same query language.

dasel -f config.yaml '.database.host'

dasel put -f config.json '.version' -v '2.0'

**gron — make JSON greppable**

By Tom Hudson (TomNomNom). Flattens JSON into one-line key=value statements.

gron https://api.github.com/users/torvalds | grep public_repos

json.public_repos = 7;

Each tool **slots naturally into a shell pipeline**. That's the point — the shell's ability to deal with JSON/YAML leapt forward in the 2020s.

Chapter 16 · Parallel execution — xargs · parallel · rush

**`xargs -P`** — the simplest parallelism

8 concurrent gzips

ls *.log | xargs -n 1 -P 8 gzip

null-terminated input (safe for tricky filenames)

find . -name '*.log' -print0 | xargs -0 -n 1 -P 8 gzip

**GNU parallel** — Ole Tange's richer engine

parallel -j 8 gzip ::: *.log

parallel --bar 'convert {} {.}.png' ::: *.jpg

parallel --eta wget {} ::: $(cat urls.txt)

GNU parallel has tricky quoting, but supports ETA, progress bars, retry, and remote SSH-distributed execution.

**rush** — shenwei356's (China) Go implementation, easier quoting

rush 'echo Hello, {}' ::: a b c

rush -j 8 'gzip {}' ::: $(ls *.log)

**When to use what**

- Simple parallelism → `xargs -P`. Fast and everywhere.

- Progress bars / retries needed → `parallel`.

- Quoting headaches → `rush`.

Chapter 17 · gum · charm — pretty TUIs from the shell

Charm.sh, run by Toby Padilla and Christian Rocha, is a collection of Go libraries and tools. They turn shell scripts into pretty interactive UIs.

User input (text, multi-select, confirm)

NAME=$(gum input --placeholder "Your name?")

ENV=$(gum choose dev staging prod)

gum confirm "Really deploy?" && deploy.sh "$ENV"

Spinner

gum spin --spinner dot --title "building..." -- ./build.sh

Colored output

gum style --foreground 212 --bold "success!"

Markdown rendering

gum format -- "# Title" "**bold**"

**Why it matters**

A bash script's interactive UI usually ends at `read`. gum lifts that into the modern era — color, spinner, multi-select, file picker. Great for CI/CD review tools, demos, and setup wizards.

**Charm's other tools**

- **glow** — markdown rendering in the terminal.

- **vhs** — scripted terminal GIF recording.

- **bubble tea** — Go TUI framework. lazygit, k9s belong to the same family.

Chapter 18 · just · task · xc · mise — modern task runners

**just** — Casey Rodarmor's modern Makefile

May 2026 sits at 1.40. Written in Rust. Keeps Makefile's good parts and drops the gotchas.

justfile

default: build test

build:

cargo build --release

test:

cargo test

deploy env="dev":

@echo "Deploying to {{env}}"

./scripts/deploy.sh {{env}}

Call bash directly

notes:

#!/usr/bin/env bash

set -euo pipefail

grep -r "TODO" src/

**Why just beats Makefile**

- No tabs-vs-spaces drama.

- Consistent variable expansion (Make's `$$` vs `$` confusion is gone).

- Clearer dependency syntax (`recipe-name: dep1 dep2`).

- No `.PHONY` ceremony — running commands is the default.

**task (taskfile.dev)** — YAML-based

Taskfile.yml

version: '3'

tasks:

build:

cmds:

- go build ./...

test:

deps: [build]

cmds:

- go test ./...

**xc** — task runner that lives in markdown

By Joe Brockwill. Define tasks as code blocks in a README.md.

build

cargo build --release

test

Requires: build

cargo test

**mise (formerly rtx)** — version manager + task runner

Jordan Pittman's Rust tool. Began as an asdf successor; now also ships task running.

.mise.toml

[tools]

node = "20"

python = "3.12"

[tasks.build]

run = "npm run build"

**Selection criteria**

- Simple command bundles → just. Lightest and most intuitive.

- Complex dependency graphs → task (taskfile).

- Version pinning too → mise.

- Self-documenting → xc.

Chapter 19 · Shell prompts — Starship · Oh My Posh · Powerline

**Starship — universal, fast, Rust-built prompt**

Matan Kushner and Tim Sosa started it in 2019. Supports bash, zsh, fish, PowerShell, Nushell, ion, elvish, tcsh, xonsh, cmd. Configured by a single TOML file.

~/.config/starship.toml

add_newline = false

format = "$directory$git_branch$git_status$character"

[directory]

truncation_length = 3

truncate_to_repo = true

[git_branch]

symbol = " "

[character]

success_symbol = "[➜](bold green)"

error_symbol = "[➜](bold red)"

bash

eval "$(starship init bash)"

zsh

eval "$(starship init zsh)"

fish

starship init fish | source

**Oh My Posh — cross-shell, Windows-friendly**

Jan De Dobbeleer's work. Originally PowerShell-only, now everywhere. Popular with Windows users. 100+ themes.

**Powerline — legacy**

Written in Python. Pioneered the first "pretty prompt" generation. Effectively unused in 2026 — Starship took over almost every slot.

**Why Starship became standard**

1) Shell-independent — one config file gives the same prompt anywhere. 2) Fast — Rust-built with background caching. 3) The right information — git branch, language version, Kubernetes context, AWS profile, all auto-detected.

Chapter 20 · AI shells — sgpt · gptme · Warp · Amazon Q

**shell_gpt (sgpt) — TheR1D**

Python-based. Calls the OpenAI API from the shell.

sgpt "find all .log files modified today"

Output: find . -name "*.log" -mtime -1

sgpt --shell "compress all png in this dir"

(Enter to execute, e to edit)

sgpt --code "fibonacci in rust"

**gptme — Bjorn Holm**

Same concept but supports multi-turn conversations and tool calls (read/write/run files). Local LLMs also plug in.

**Warp Terminal — the AI-first terminal**

Run by Zach Lloyd since 2022. Linux support landed in 2024 and stable in 2025. AI command suggestions, AI explain command, notebooks. Free and Pro plans exist.

Warp's # command

how do I rebase from main?

→ Warp suggests the git rebase command and you Enter to run

**Amazon Q Developer (formerly Fig)**

Amazon acquired Fig in 2024 and merged it into the Amazon Q Developer CLI. Completion got stronger and natural-language command generation arrived.

**Aiken · Codex CLI**

Anthropic Claude Code, GitHub Copilot CLI, OpenAI Codex CLI and similar tools claimed their seat as "agents" that execute shell commands directly. The shell is now an interface for **agents, not only humans**.

**Two models for shell + AI**

1) **Suggest mode** — AI proposes a command; the human confirms (sgpt, Warp).

2) **Agent mode** — AI runs the shell directly, observes results, and chooses the next move (Claude Code, Codex CLI).

Agent mode is risky, so containerized or sandboxed execution is the safer pattern.

Chapter 21 · Terminal emulators — Ghostty · Wezterm · Alacritty · Kitty · iTerm2

**Ghostty — Mitchell Hashimoto's new project**

The HashiCorp co-founder (Vagrant, Packer, Terraform) Mitchell Hashimoto launched Ghostty in 2024, with 1.0 stable in 2025 and 1.2 by May 2026. Written in Zig with GPU acceleration, native macOS plus Linux. The signatures: "the defaults are excellent" and "native macOS integration."

~/.config/ghostty/config

font-family = "JetBrains Mono"

font-size = 14

theme = "Catppuccin Mocha"

window-padding-x = 8

window-padding-y = 8

**Wezterm — Wez Furlong**

Written in Rust. Configured in Lua. Tabs/panes, ligatures, embedded SSH client.

local wezterm = require 'wezterm'

return {

font = wezterm.font 'JetBrains Mono',

font_size = 14,

color_scheme = 'Dracula',

hide_tab_bar_if_only_one_tab = true,

}

**Alacritty — Joe Wilm**

Rust-built. Among the fastest terminals. TOML config. No tabs/panes (use with tmux).

**Kitty — Kovid Goyal**

Python plus GPU. Strong image protocol (can display PNG directly).

**iTerm2 — George Nachman**

The macOS classic. Profiles, hotkeys, split panes, search, broadcast — feature dense. Still a macOS standard in 2026.

**Hyper · Tabby**

Electron-based. Low adoption — heavy with weak GPU acceleration.

**Selection criteria**

- macOS lightweight → Ghostty or iTerm2.

- Cross-platform lightweight → Alacritty (+tmux) or Kitty.

- Rich configuration → Wezterm.

- AI integration → Warp.

Chapter 22 · Korea/Japan ops culture — Coupang · LINE · Cybozu · Mercari

**Korea — Coupang shell ops**

Coupang's infrastructure ops team handles massive traffic and, since the early 2020s, has standardized on **bash + Ansible + Terraform**. Shell best practices (strict mode, ShellCheck CI gate) have been adopted as PR rules internally, as their Korean conference talks (if-kakao, AWS Summit Seoul) describe.

**Korea — Kakao and the origin of fzf**

The fzf you met in chapter 13 is the work of Junegunn Choi, a former Kakao engineer. He first built fzf inside Kakao and later open-sourced it on GitHub, where it became a global standard. It counts among the most influential pieces of open source ever shipped by a Korean developer.

**Japan — LINE shell operations**

LINE runs a huge fleet of microservices out of Tokyo. Posts from the LINE Engineering blog covering internal shell-script conventions in the late 2010s are frequently cited in both Korea and Japan — strict mode, mktemp, trap, and ShellCheck are all mandatory.

**Japan — Cybozu's operational tooling**

Cybozu's Kintone team built ops tools in a bash + Ruby + Go combo for years. Internal tools like `kintone-cli` written in bash are documented on Cybozu Developer Network.

**Japan — Mercari's SRE shell culture**

Mercari, running GCP-based microservices, has publicly described (at SRE NEXT, SREcon) a policy of minimizing shell scripting and replacing it with Go CLIs. Yet they still hold bash as the standard for boot, debugging, and emergency ops.

**Shared patterns**

All three companies share: 1) mandatory `set -euo pipefail`, 2) ShellCheck as a CI gate, 3) rewriting scripts over 1,000 lines in Go/Python, 4) standardizing on `#!/usr/bin/env bash`.

Chapter 23 · Where the shell goes 2026–2028

**Outlook 1 — Bash 5.3 to 6.0**

5.3 arrives within 2026, and 6.0 likely lands around 2027–2028. No big shifts — Bash's philosophy is "don't break compatibility." Internal cleanup, performance, and error messages keep improving.

**Outlook 2 — fish 4's Rust effect**

Since the 2024 Rust rewrite, start-up time and memory have dropped sharply. 2026–2028 should bring more external contributors and faster delivery of new features (structured data, etc.).

**Outlook 3 — Nushell crossing the threshold**

Entering production scripting is still hard, but it is solidifying its place as an interactive shell for data engineers and cloud operators. Once 1.0 ships (predicted 2027) adoption will accelerate.

**Outlook 4 — AI integration standardization**

Agent-mode shell usage will go mainstream. Along with it, **sandboxing**, **permission limits**, and **command logging** will become built-in features of the shell. Agents like Claude Code and Codex CLI treat the shell as a "second user."

**Outlook 5 — Rust rewrites of core tools**

ripgrep, fd, eza, bat, bottom, just, mise, Starship — nearly every modern tool is already Rust. By 2028 we'll likely see the "Unix-core-tool generation change to Rust" mostly complete.

**Outlook 6 — POSIX's place**

POSIX shell isn't going anywhere. It survives as init script, Docker `alpine`, embedded Linux, and the lowest common denominator of CI matrices. So **portable scripts should still ship `#!/bin/sh`** as the best practice.

Chapter 24 · Shell scripting checklist (10 items)

Ten things to verify every time you write a shell script.

1. **shebang** — `#!/usr/bin/env bash` or, when portable, `#!/bin/sh`.

2. **strict mode** — `set -Eeuo pipefail` on the second line.

3. **IFS** — `IFS=$'\n\t'` for safety on filenames with spaces.

4. **mktemp** — always `mktemp -d` for temporaries with `trap '...' EXIT` to clean up.

5. **Quoting** — `$var` is almost always quoted as `"$var"`. `${arr[@]}` becomes `"${arr[@]}"`.

6. **Exit codes** — function results to stdout, success is 0, failure is non-zero.

7. **shellcheck** — required in CI. Suppress warnings explicitly with `# shellcheck disable=...`.

8. **shfmt** — formatting consistency. Run as a pre-commit hook.

9. **Error messages** — send to stderr (`>&2`) and exit with a specific code.

10. **Documentation** — top comment block with usage, arguments, dependencies, examples.

Chapter 25 · A catalog of seven real-world anti-patterns

**Anti-pattern 1 — unquoted variables**

Dangerous

rm $file # explodes if $file has spaces or globs

Safe

rm -- "$file"

**Anti-pattern 2 — relying on `set -e` without `pipefail`**

In `curl ... | jq .x`, if curl fails but jq succeeds on empty input, the pipeline looks successful.

**Anti-pattern 3 — not checking `cd`**

Dangerous

cd /tmp/build

rm -rf * # if cd fails, you blow up the current directory

Safe

cd /tmp/build || exit 1

rm -rf -- ./*

**Anti-pattern 4 — mixing `[ ]` and `[[ ]]`**

Bash uses `[[ ]]` (a keyword). Use `[ ]` only for POSIX compatibility. Do not mix.

**Anti-pattern 5 — backticks (\`cmd\`)**

Use `$(cmd)`. Nestable, quoting-safe, more readable.

**Anti-pattern 6 — `eval`**

Never feed user input to `eval`. There is nearly always another way (arrays, functions, `bash -c "$(...)"`).

**Anti-pattern 7 — a monstrous single script**

Over 1,000 lines? Consider rewriting in Go/Python. The shell's strength is glue — wiring other tools together. Business logic belongs in a real language.

Chapter 26 · Conclusion — the shell still sits in the middle of infrastructure

37 years ago when Brian Fox first released bash, he was building "a free Bourne shell replacement" as part of GNU. That single decision now lives at the innermost layer of nearly every computer.

The 2026 shell landscape summarized:

- **Bash 5.2** is the standard — works everywhere, the scripting default.

- **Zsh 5.9** is macOS default — interactive only.

- **fish 4** is reborn in Rust — friendly interactive.

- **Nushell** is the structured-data shell — for data engineers and cloud operators.

- **ShellCheck + shfmt + bashly** are the heart of the modern workflow.

- **fzf, ripgrep, fd, bat, eza, just, mise, Starship** are the next-generation tools.

- **gum** brings pretty TUIs to the shell.

- **sgpt, Warp, Claude Code** ship AI integration.

- **Ghostty, Wezterm, Alacritty, Kitty** are the next-gen terminals.

The shell isn't going away. It grows richer, safer, and more expressive. Our job is to pick the right tools, write robustly with strict mode and shellcheck, and have the courage to leave the shell when scripts exceed 1,000 lines.

> The shell lives at the center of operations. As long as operations exist, the shell does too.

References

1. GNU Bash Manual — [https://www.gnu.org/software/bash/manual/](https://www.gnu.org/software/bash/manual/)

2. Bash 5.2 Release Notes — [https://lists.gnu.org/archive/html/bug-bash/2022-09/msg00214.html](https://lists.gnu.org/archive/html/bug-bash/2022-09/msg00214.html)

3. Zsh Documentation — [https://zsh.sourceforge.io/Doc/](https://zsh.sourceforge.io/Doc/)

4. Oh My Zsh — [https://ohmyz.sh/](https://ohmyz.sh/)

5. fish shell — [https://fishshell.com/](https://fishshell.com/)

6. Nushell Book — [https://www.nushell.sh/book/](https://www.nushell.sh/book/)

7. Murex — [https://murex.rocks/](https://murex.rocks/)

8. xonsh — [https://xon.sh/](https://xon.sh/)

9. Elvish — [https://elv.sh/](https://elv.sh/)

10. ShellCheck — [https://www.shellcheck.net/](https://www.shellcheck.net/)

11. shfmt (mvdan) — [https://github.com/mvdan/sh](https://github.com/mvdan/sh)

12. bashly — [https://bashly.dannyb.co/](https://bashly.dannyb.co/)

13. gum (Charm) — [https://github.com/charmbracelet/gum](https://github.com/charmbracelet/gum)

14. fzf — [https://github.com/junegunn/fzf](https://github.com/junegunn/fzf)

15. ripgrep — [https://github.com/BurntSushi/ripgrep](https://github.com/BurntSushi/ripgrep)

16. fd — [https://github.com/sharkdp/fd](https://github.com/sharkdp/fd)

17. bat — [https://github.com/sharkdp/bat](https://github.com/sharkdp/bat)

18. eza — [https://github.com/eza-community/eza](https://github.com/eza-community/eza)

19. bottom — [https://github.com/ClementTsang/bottom](https://github.com/ClementTsang/bottom)

20. just — [https://github.com/casey/just](https://github.com/casey/just)

21. taskfile.dev — [https://taskfile.dev/](https://taskfile.dev/)

22. mise — [https://mise.jdx.dev/](https://mise.jdx.dev/)

23. Starship — [https://starship.rs/](https://starship.rs/)

24. Oh My Posh — [https://ohmyposh.dev/](https://ohmyposh.dev/)

25. Warp — [https://www.warp.dev/](https://www.warp.dev/)

26. Ghostty — [https://ghostty.org/](https://ghostty.org/)

27. Wezterm — [https://wezfurlong.org/wezterm/](https://wezfurlong.org/wezterm/)

28. Alacritty — [https://alacritty.org/](https://alacritty.org/)

29. POSIX Shell Standard — [https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html](https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html)

30. Google Shell Style Guide — [https://google.github.io/styleguide/shellguide.html](https://google.github.io/styleguide/shellguide.html)

현재 단락 (1/571)

June 1989. Brian Fox released the first version of the Bourne-Again SHell as part of the GNU Project...

작성 글자: 0원문 글자: 32,887작성 단락: 0/571