Терминал: навигация и базовые команды

Терминал: навигация и базовые команды

Терминал - это не «хакерское окошко». Это основной инструмент работы с сервером. GUI на продакшен-сервере обычно нет.

Навигация по файловой системе

pwd                    # где я сейчас (print working directory)
ls                     # что здесь лежит
ls -la                 # подробно, включая скрытые файлы
cd /var/log            # перейти в каталог
cd ..                  # на уровень вверх
cd ~                   # домой
cd - # назад, где был
Нажми Tab после первых букв - терминал дополнит имя файла или каталога. Двойной Tab покажет варианты. Это экономит часы.

Структура файловой системы Linux

/
├── bin/       # базовые утилиты (ls, cat, grep)
├── etc/       # конфиги (nginx.conf, .env)
├── home/      # домашние каталоги пользователей
├── var/
│   ├── log/   # логи сервисов
│   └── www/   # веб-контент (иногда)
├── tmp/       # временные файлы
├── opt/       # стороннее ПО
└── usr/       # пользовательские программы

Запомни: конфиги в /etc, логи в /var/log, твой код обычно в /opt или /home.

Просмотр файлов

cat file.txt           # весь файл (осторожно с большими)
head -20 file.txt      # первые 20 строк
tail -50 file.txt      # последние 50 строк
tail -f /var/log/app.log  # следить за логами в реальном времени
less file.txt          # постраничный просмотр (q - выход)
`cat` выведет всё в терминал и подвесит сессию. Для больших файлов - `less`, `head`, `tail` или `grep`.

Поиск

grep "error" app.log           # строки с "error"
grep -i "error" app.log        # без учёта регистра
grep -r "TODO" ./src/          # рекурсивно по каталогу
grep -n "panic" main.go        # с номерами строк

Создание и удаление

mkdir -p projects/backend      # создать вложенные каталоги
touch README.md                # создать пустой файл
cp file.txt backup.txt         # копировать
mv old.txt new.txt             # переименовать / переместить
rm file.txt                    # удалить файл
rm -r directory/               # удалить каталог
`rm -rf` удаляет без подтверждения и без корзины. Всегда проверь путь дважды. На сервере нет Ctrl+Z.

Пайпы и перенаправление

Pipe и редиректы: stdin, stdout, stderr через символы конвейера

Пайп | - это конвейер: выход одной команды становится входом другой.

cat app.log | grep "error" | wc -l     # сколько ошибок в логе
ps aux | grep nginx                     # найти процесс nginx
ls -la | sort -k5 -n                    # файлы по размеру

Перенаправление:

echo "hello" > file.txt    # записать (перезапишет!)
echo "world" >> file.txt   # дописать в конец
command 2>&1               # stderr в stdout
command > /dev/null 2>&1   # подавить весь вывод

Горячие клавиши терминала

КлавишаДействие
Ctrl+CПрервать команду
Ctrl+DВыход из shell
Ctrl+RПоиск по истории команд
Ctrl+LОчистить экран
Ctrl+A / Ctrl+EВ начало / конец строки
Ctrl+WУдалить слово слева
Ctrl+U / Ctrl+KУдалить до начала / конца строки
Ctrl+ZПриостановить процесс (см. ниже)

Job control: процессы переднего и заднего плана

Запустил долгую команду и понял, что хочешь освободить терминал? Тебе нужен job control.

sleep 300                # запустил на переднем плане - терминал занят
# Ctrl+Z                 # → пауза процесса
jobs                     # [1]+  Stopped    sleep 300
bg                       # → продолжить в фоне (& суффикс эквивалент при запуске)
jobs                     # [1]+  Running    sleep 300 &
fg                       # → вернуть на передний план
# Сразу запустить в фоне
long-script.sh &
[1] 12345                # bash сообщил job-id [1] и PID 12345

# Список фоновых задач
jobs -l
[1]+ 12345 Running   long-script.sh &

# Убить процесс
kill %1                  # по job-id
kill 12345               # по PID
kill -9 12345            # SIGKILL - только если не реагирует на обычный kill

nohup и disown: процесс переживёт закрытие терминала

# По умолчанию: закроешь ssh - фоновые процессы умрут (SIGHUP)
./deploy.sh &

# nohup - игнорировать SIGHUP, перенаправить вывод в nohup.out
nohup ./deploy.sh &
nohup ./deploy.sh > deploy.log 2>&1 &     # перенаправление логов своё

# disown - отвязать УЖЕ запущенный фоновый процесс от shell
./deploy.sh &
disown -h %1                              # процесс продолжит работать после exit
nohup годится для разового запуска. Для развёртываний, миграций, прогона тестов - используй `tmux` или `screen`: можешь отключиться (Ctrl+B D) и подключиться позже (`tmux attach`), увидеть весь вывод и состояние.

История команд: !!, !$, Ctrl+R

# Ctrl+R: интерактивный поиск по истории
# (reverse-i-search)`docker`: docker compose up -d
# жмёшь Ctrl+R ещё раз - следующий матч; Enter - выполнить; Esc - отредактировать

# History expansion
!!                       # последняя команда
sudo !!                  # та же команда с sudo (классика)
!$                       # последний аргумент предыдущей команды
!*                       # все аргументы
!ssh                     # последняя команда, начинающаяся на "ssh"
^foo^bar                 # повторить последнюю, заменив foo на bar

history                  # вся история (~/.bash_history)
history | grep docker    # найти что искал
!42                      # выполнить команду номер 42 из истории
# Пример из жизни
$ wget https://example.com/big-file.tar.gz
$ sha256sum !$
sha256sum https://example.com/big-file.tar.gz   # подставится URL, не файл
# Правильный сценарий:
$ wget https://example.com/big-file.tar.gz
$ ls -la !*:t                                    # :t = «basename»
`export TOKEN=abc123` тоже попадёт в `.bash_history`. Чтобы команда НЕ записалась - поставь **пробел в начале** (если включено `HISTCONTROL=ignorespace`) или используй `read -s TOKEN`. Никогда не хардкодь токены в скрипты.

Tab completion: bash-completion

# Базовое: имена файлов и команд
$ ls /var/lo<Tab>        # → /var/log/
$ git che<Tab>           # → git checkout (если установлен bash-completion)

# Двойной Tab показывает варианты
$ git <Tab><Tab>
add        branch     checkout   clone      commit     ...
# Установка programmable completion (если ещё нет)
sudo apt install bash-completion             # Debian/Ubuntu
brew install bash-completion@2               # macOS

# В .bashrc:
[ -f /etc/bash_completion ] && . /etc/bash_completion

Многие инструменты идут с собственными completion-скриптами:

docker completion bash > /etc/bash_completion.d/docker
kubectl completion bash > /etc/bash_completion.d/kubectl
gh completion -s bash > /etc/bash_completion.d/gh

Теперь kubectl get po<Tab> дополнит «pods», а docker exec <Tab> покажет список запущенных контейнеров.

Aliases vs functions vs scripts

Три способа сохранить «свою» команду - у каждого своя ниша:

# 1. alias - простая подмена строки
alias ll='ls -la'
alias gst='git status'
alias dcd='docker compose down'
# В ~/.bashrc или ~/.aliases (последний source-ить из bashrc)
# 2. function - нужны аргументы или логика
mkcd() {                          # mkdir + cd одной командой
    mkdir -p "$1" && cd "$1"
}
gco() {                           # git checkout с подсказкой
    if [ -z "$1" ]; then
        git branch
    else
        git checkout "$1"
    fi
}
# 3. shell script - пере-используется, расшарен с командой
# ~/bin/deploy-staging
#!/usr/bin/env bash
set -euo pipefail
ssh staging "cd /app && git pull && docker compose up -d --build"

chmod +x ~/bin/deploy-staging
echo 'export PATH="$HOME/bin:$PATH"' >> ~/.bashrc
Когда выбирать       Сигнал
──────────────       ──────────────────────────────────────────
alias                подмена строки 1:1; без логики, без аргументов
function             нужны позиционные аргументы или условия;
                      живёт в shell-сессии; легко переопределить
script               длинная логика, шарится между людьми, версионируется
                      в Git; запускается из любого shell (не зависит от bash)

Shebang: #!/usr/bin/env bash vs #!/bin/bash

#!/bin/bash             # жёстко привязан к /bin/bash

На macOS системный /bin/bash - древний 3.2 (из-за GPLv3); на NixOS или Alpine его вообще нет (там /bin/sh ≠ bash). Скрипт упадёт «No such file or directory».

#!/usr/bin/env bash     # ищет bash в PATH - работает везде

env сам находит интерпретатор по $PATH. Бонус: можно поставить новую версию bash через brew/apt - она подхватится автоматически.

#!/bin/sh               # POSIX shell - НЕ bash; нет массивов, нет [[ ]],
                        # нет process substitution <(...) - только то,
                        # что есть в /bin/dash (на Debian sh = dash)

Не путай #!/bin/sh и #!/usr/bin/env bash. Если используешь bash-фичи ([[, массивы, ${var,,}) - указывай bash явно.

В каждом серьёзном bash-скрипте первой строкой после shebang ставь `set -euo pipefail`: `-e` упасть на любой ошибке, `-u` ругаться на необъявленные переменные, `-o pipefail` ловить ошибки в пайпах. Это превращает bash из «как-нибудь» в «строго».

Мини-задание

  • Перейди в /var/log и найди файл syslog или messages
  • Посмотри последние 20 строк этого файла через tail -20
  • Найди все строки с «error» через grep -i "error"
  • Посчитай их: grep -ic "error" syslog

Итог

  • pwd, ls, cd - навигация. cat, head, tail, less - просмотр. grep - поиск.
  • Пайпы (|) - суперсила терминала. Комбинируй простые команды для сложных задач.
  • Tab для автодополнения, Ctrl+R для поиска по истории - привыкай сразу.

Типичная ошибка

Копировать команды из Stack Overflow, не читая. rm -rf с неправильным путём, chmod 777 на всё подряд, curl | bash без проверки скрипта - всё это реальные инциденты. Читай, что запускаешь.

Мини-практика

Создай каталог ~/linux-practice. Внутри создай 5 файлов: app.log, error.log, config.yml, main.go, README.md. Запиши в app.log несколько строк с помощью echo "..." >>. Потом найди в нём все строки с определённым словом через grep и посчитай их количество через wc -l.

Зарегистрируйтесь бесплатно, чтобы пройти квиз, решить задание с автопроверкой и вести прогресс.