Каждый, кто проводит в терминале значительную часть рабочего дня, знает это состояние: пальцы уже наизусть выбивают длинную команду, а желание сократить её до двух букв становится почти физическим. Системный администратор набирает за смену сотни строк, и каждый лишний десяток символов отнимает секунды. На неделе набегают минуты, за год складываются рабочие дни, потраченные на перепечатывание одного и того же.

Оболочка Bash решает проблему штатными средствами. Алиасы сворачивают длинные команды в короткие псевдонимы, функции принимают аргументы и собирают из простых команд полноценные инструменты, переменная CDPATH и стек каталогов ускоряют перемещение по дереву директорий, а настройка цветов превращает чёрно-белый вывод в наглядную картину. Всё это живёт в текстовом файле ~/.bashrc, правится любым редактором и применяется командой source. Дальше собраны готовые к копированию приёмы, от простых сокращений до закладок на часто посещаемые каталоги.

Алиас как короткая обёртка над длинной командой в ~/.bashrc

Идея алиаса предельно проста. Команда alias связывает короткое имя с длинным значением, и оболочка, встретив имя в начале строки, подставляет вместо него сохранённый текст. Классика жанра выглядит так:

alias ll='ls -alF'

Проверить, что скрыто за сокращением, помогает команда type:

$ type ll
ll is aliased to `ls -alF'

Команда alias без аргументов печатает все псевдонимы, unalias ll удаляет один из них, а unalias -a вычищает сразу всё. Просматривать список полезно: за годы конфиг обрастает десятками строк, про половину которых никто не помнит.

Несколько правил поведения алиасов сэкономят время на отладку. Раскрытие включено только в интерактивной оболочке, поэтому внутри скриптов алиасы не действуют, там работают функции. Определение ставят на отдельную строку: bash раскрывает алиасы в момент чтения, так что объявление в той же строке, где команда используется, сработает только со следующей. В значении алиаса не подставить аргументы, и потому опытные пользователи повторяют: почти для любых задач функции предпочтительнее алиасов.

Из этого правила есть красивое исключение с завершающим пробелом. Если значение алиаса оканчивается пробелом, оболочка проверяет на раскрытие ещё и следующее слово. Отсюда трюк:

alias sudo='sudo '

Теперь sudo ll честно развернёт ll, хотя раньше она заканчивалась сообщением, что ll не найдена. Одна строка в конфиге, и разграничение "алиасы для себя, полный путь для sudo" больше не нужно.

Хранить сокращения разумно в ~/.bashrc: интерактивная оболочка читает его при каждом запуске. В Debian и Ubuntu в стандартном .bashrc есть блок, который подключает отдельный файл ~/.bash_aliases, если тот существует, и свои сокращения удобно держать именно там. После правок файл применяется без перезапуска терминала:

source ~/.bashrc

Рабочий набор сокращений для повседневных задач и защита от неосторожного удаления

Писать алиасы лучше под собственные привычки, но есть фонд проверенных строк, которые переезжают из конфига в конфиг:

# Список файлов
alias ls='ls --color=auto'
alias ll='ls -alFh'
alias la='ls -A'

# Навигация
alias ..='cd ..'
alias ...='cd ../..'
alias ....='cd ../../..'

# Читаемый вывод
alias grep='grep --color=auto'
alias df='df -h'
alias du='du -h'
alias free='free -h'
alias ports='ss -tulpn'

# Безопасность и удобство
alias mkdir='mkdir -pv'
alias cp='cp -iv'
alias mv='mv -iv'
alias rm='rm -I'
alias ping='ping -c 5'

# Мелочи
alias serve='python3 -m http.server 8000'

Каждая строка здесь закрывает конкретную занозу. Модификаторы -i у cp и mv заставляют команду спросить подтверждение перед перезаписью файла, ключ -v печатает, что именно скопировано или переименовано. rm с ключом -I задаёт один общий вопрос, только если удаляется больше трёх файлов или запрошено рекурсивное удаление, и не досаждает вопросами при одиночном файле. ping без ключа в Linux не останавливается сам, а -c 5 ограничивает вывод пятью пакетами. Сокращение ports показывает слушающие сокеты, для колонки с именами процессов нужны права суперпользователя. В стандартном .bashrc Debian и Ubuntu алиасы для ls и grep с --color уже прописаны, остальное стоит добавить самому.

Отдельная песня алиас mkdir='mkdir -pv'. Ключ -p создаёт всю цепочку вложенных каталогов разом и молчит, если каталог уже существует, а -v печатает созданный путь. Комбинация экономит время и нервы, когда разворачиваешь проект с глубокой структурой.

Функции Bash с аргументами там, где алиас бессилен

Как только команде нужно передать параметр, алиас сдаётся. Внутри его значения конструкция $1 останется буквальным текстом, и bash честно попытается найти файл с именем $1. Функции устроены иначе: они принимают позиционные параметры $1, $2 и далее по порядку, видят их количество в переменной $# и умеют объявлять локальные переменные словом local, чтобы не засорять сессию. Синтаксис такой:

имя_функции() {
    команда "$1"
}

Первая функция, которую стоит завести, создаёт каталог и сразу переходит в него:

mkcd() {
    mkdir -p -- "$1" && cd -- "$1" || return
}

Вторая решает задачу подъёма по дереву. Чтобы подняться на три уровня, обычно пишут cd ../../.., и легко ошибиться в количестве точек:

up() {
    local count="${1:-1}"
    local path=""
    for ((i = 0; i < count; i++)); do
        path+="../"
    done
    cd "$path" || return
}

Вызов up 3 поднимает на три уровня, а без аргумента функция работает как переход на один уровень выше, благодаря значению по умолчанию ${1:-1}. Третья ищет файл по подстроке имени, не отвлекаясь на регистр и потоки ошибок:

ff() {
    find . -type f -iname "*$1*" 2>/dev/null
}

Вызов ff config найдёт nginx.conf, myconfig.sh и всё, что содержит слово в имени. Три функции, полтора десятка строк, а эффект ощутимый: каждая вызывается десятки раз в день. Разросшийся конфиг инспектируют командой declare -f имя, печатающей код функции, и declare -F, показывающей список имён.

Быстрое перемещение по дереву каталогов с CDPATH и стеком директорий

Когда проект разложен на уровни вложенности, каждый переход превращается в длинный прыжок. Bash предлагает несколько штатных ускорителей, и первый включается одной строкой:

shopt -s autocd cdspell dirspell

autocd позволяет переходить в каталог простым набором его имени, без cd. cdspell исправляет мелкие опечатки: переставленные символы, пропущенный или лишний знак, печатает исправленное имя и выполняет переход. dirspell делает то же при автодополнении по Tab. Три опции, и опечатки перестают быть помехой.

Переменная CDPATH работает как поисковый путь: cd ищет запрошенный каталог не только в текущей директории, но и в перечисленных базовых каталогах:

export CDPATH=".:$HOME/projects:/srv/www"

После такой строки команда cd webapp из любого места найдёт ~/projects/webapp. Точка в начале списка важна: пустой элемент пути означает текущий каталог, и приоритет локальных каталогов уберегает от сюрпризов. При переходе через CDPATH bash печатает полный путь назначения, так что всегда видно, куда попал.

Для возвратов между парой каталогов есть стек. pushd каталог делает переход и запоминает предыдущую директорию, dirs -v печатает стек с номерами, popd возвращает назад, а pushd без аргументов меняет местами две верхние записи. Аналог в миниатюре встроен в cd: команда cd - переносит в предыдущую директорию из переменной OLDPWD и печатает путь.

Наконец, закладки на часто посещаемые каталоги удобно держать в ассоциативном массиве:

declare -A BOOKMARKS=(
    [dev]="$HOME/projects/webapp"
    [logs]="/var/log/nginx"
)

bm() {
    if [ "$1" = "add" ]; then
        BOOKMARKS["$2"]="$PWD"
        echo "Закладка $2 добавлена"
    else
        cd "${BOOKMARKS[$1]}" || echo "Закладки $1 нет"
    fi
}

bm logs мгновенно переносит в каталог логов, bm add new запоминает текущую директорию под именем new. Ассоциативные массивы появились в Bash 4, вышедшем в 2009 году, так что код работает на любой современной системе.

Цвет в терминале не украшение, а способ быстрее считывать информацию. Управляют им escape-последовательности вида \e[...m, где после \e[ идёт код: 0 сбрасывает оформление, 1 включает жирность, 30-37 задают цвет текста, 40-47 цвет фона, 90-97 дают яркие оттенки. Приглашение настраивается переменной PS1, и рабочий вариант выглядит так:

PS1='\[\e[01;32m\]\u@\h\[\e[00m\]:\[\e[01;34m\]\w\[\e[00m\]\$ '

Пользователь и хост печатаются жирным зелёным, путь синим. Скобки \[ и \] обрамляют непечатаемые символы, без них bash неверно считает длину строки, и при листании истории курсор уезжает. Сокращения простые: \u имя пользователя, \h хост до первой точки, \w полный путь с тильдой вместо домашнего каталога, \$ решётка для суперпользователя и доллар для остальных. Длинные пути сокращает PROMPT_DIRTRIM: значение 2 оставляет в \w два последних компонента, заменяя обрезанное многоточием.

В проектах с git имя ветки в приглашение переносит функция, вызываемая прямо из PS1:

parse_git_branch() {
    git branch 2>/dev/null | sed -n 's/^\* \(.*\)$/ (\1)/p'
}
PS1='\[\e[01;32m\]\u@\h\[\e[00m\]:\[\e[01;34m\]\w\[\e[00m\]\[\e[33m\]$(parse_git_branch)\[\e[00m\]\$ '

Одинарные кавычки здесь принципиальны: bash пересчитывает подстановку при каждом выводе приглашения, и ветка в жёлтом цвете всегда актуальна.

Цветами управляет и ls. Утилита dircolors печатает готовую строку с экспортом LS_COLORS, а dircolors -p показывает базу с кодами. По умолчанию каталоги получают 01;34, жирный синий, исполняемые файлы 01;32, зелёный, ссылки 01;36, бирюзовый, архивы вроде *.tar 01;31, красный. Перекрасить каталоги можно, поставив своё значение впереди:

export LS_COLORS="di=01;36:$LS_COLORS"

grep с ключом --color подсвечивает совпадения, настройка лежит в GREP_COLORS. По умолчанию найденный текст выделяется кодом 01;31, жирным красным, имена файлов 35, номера строк 32, разделители контекста 36. Поменять только подсветку совпадений можно так:

export GREP_COLORS='ms=01;36'

Для разовых сообщений в скриптах годится echo с ключом -e и теми же кодами:

echo -e "\e[1;33mВнимание, проверь конфиг\e[0m"

Код 1;33 включает жёлтый жирный текст, а \e[0m в конце обязателен, иначе цвет останется на всём, что выводится дальше. Кто не хочет запоминать escape-коды, использует tput: tput setaf 3 даёт жёлтый, tput bold жирность, tput sgr0 сброс. Современные терминалы понимают и 256 цветов, код \e[38;5;208m даёт оранжевый. Подсветку освоили и сами инструменты: gcc раскрашивает сообщения об ошибках с ключом -fdiagnostics-color=auto, свежие версии GNU diff поддерживают --color.

История команд, шорткаты и типичные ошибки при настройке алиасов

История дополняет сокращения. По умолчанию bash запоминает 500 команд, и этого мало: строки HISTSIZE=10000 и HISTFILESIZE=20000 расширяют запас, а HISTCONTROL=ignoredups:erasedups не даёт дубликатам разрастаться. Формат HISTTIMEFORMAT='%F %T ' добавляет к выводу history дату и время каждой команды. Опция shopt -s histappend заставляет оболочку дописывать историю в файл, а не перезаписывать, что спасает командную память при нескольких открытых окнах. Поиск по архиву быстрее всего выполняется сочетанием Ctrl+R: начал набирать фрагмент, и bash подставил прошлую команду.

Большинство проблем с алиасами сводится к шести ситуациям:

  1. Определение и использование в одной строке не работает, bash раскрывает алиасы при чтении строки, а не при выполнении, и новое сокращение заметит только следующая строка;
  2. Аргументы в значении алиаса не подставляются, конструкция alias g='grep $1' выведет буквально $1, для параметров нужна функция;
  3. Имя алиаса должно быть одним словом без пробелов, попытка объявить alias my cd='cd /mnt' закончится ошибкой синтаксиса;
  4. Двойные кавычки при определении подставляют переменные в момент записи строки, одинарные оставляют их до вызова, что критично для $PWD и других изменчивых значений;
  5. Правки .bashrc не действуют в уже открытых окнах терминала, нужен source ~/.bashrc или новый сеанс;
  6. Алиасы молчат в скриптах, потому что в неинтерактивной оболочке отключено раскрытие expand_aliases, и там без функций не обойтись.

Настройка алиасов и функций занимает один вечер, а отдача продолжается годами. Каждая команда из статьи вызывается десятки раз в день, и пара сэкономленных секунд на вызове складывается в часы живого времени за год. Конфиг остаётся личным документом: раз в полгода стоит просматривать его командой alias, убирать то, что не прижилось, и добавлять то, что родилось из новой рутины. Терминал от этого становится привычной средой, где длинные команды свёрнуты, переходы занимают одно слово, а важное сразу видно цветом.