Внешний вид
Bash: операторы, перенаправления, echo и sed — для автоматизации сетевика
Зачем: наладчик с bash экономит часы: автоматический опрос свитча, массовый ping подсети, разбор логов, генерация отчётов. Всё ниже — на реальных примерах из скриптов нашей лаборатории (они лежат в ~/NetLab/*.sh).
1. Коды выхода: язык «успех/ошибка» любой команды
Каждая команда в Linux завершаясь оставляет код выхода (exit code): 0 = успех, всё остальное = ошибка (конкретное число — детали). Увидеть код последней команды:
bash
ping -c1 -W1 192.168.100.1 >/dev/null && echo "было ок"
echo $? # напечатает 0 (успех) или 1 (не дотянулись)Всё в скриптинге строится на этом: условия, &&/||, if, set -e.
2. Операторы &&, ||, ;
| Оператор | Что делает | Когда использовать |
|---|---|---|
; | выполнить следующую команду всегда, независимо от результата | порядок действий без связи |
&& | выполнить следующую только если предыдущая успешна (код 0) | цепочки «и так далее, если всё ок» |
| ` | ` |
bash
# пример из нашей жизни: скопировать конфиг, и ТОЛЬКО потом перезапустить
cp chr.rsc /backup/ && ssh chr '/import file-name=chr.rsc'
# если пинг не прошёл — вывести тревогу
ping -c1 -W2 192.168.100.1 >/dev/null || echo "АЛАРМ: шлюз не отвечает"
# комбинация: попробовать основной DNS, при фейле — запасной
nslookup ya.ru 192.168.100.1 || nslookup ya.ru 1.1.1.1
# целая цепочка: обновить → поставить → перезапустить, стоп при любом фейле
apk update && apk add tcpdump && rc-service sshd restartМнемоника: && — «и тогда», || — «иначе». Читается слева направо как предложение.
3. echo и printf: печать и её подводные камни
bash
echo "Привет, сеть" # просто вывод строки
echo -n "без перевода строки" # -n убирает \n в конце
echo "переменная: $HOSTNAME" # двойные кавычки — переменные подставляются
echo 'буквально: $HOSTNAME' # одинарные — НИЧЕГО не подставляется
echo "результат: $(ip r | head -1)" # $(...) — подстановка вывода команды
printf "%-12s %s\n" "шлюз:" "192.168.100.1" # форматированный вывод (таблички!)Правило кавычек (самое частое падение новичка):
- двойные
"..."— подставляются переменные и$(...), но пробелы внутри сохраняются как одно слово; - одинарные
'...'— вообще ничего не трогается, текст как есть; - без кавычек
$varс пробелами развалится на куски — всегда пиши"$var".
4. Перенаправления: куда уходит вывод
Три «ручейка» у каждой команды: stdout (обычный вывод, fd 1), stderr (ошибки, fd 2), stdin (ввод, fd 0).
bash
команда > file # stdout → в файл (ПЕРЕЗАПИСАТЬ файл!)
команда >> file # stdout → ДОПИСАТЬ в конец файла
команда 2> err.log # stderr → в файл (ошибки отдельно)
команда > out.log 2> err.log # развести потоки по файлам
команда > all.log 2>&1 # ВСЁ в один файл (&1 = «туда же, куда stdout»)
команда 2>/dev/null # /dev/null — «чёрная дыра», молча выбросить ошибки
команда < file # подать файл на вход командыТиповая иллюстрация из нашей лабы (кейс №2):
bash
ping -c1 -W2 192.168.100.1 >/dev/null || echo "шлюз мёртв"
# ^^^^^^^^^ вывод пинга НЕ показываем юзеру, интересен только факт«Почему cat > file сразу пишет в файл»
cat без аргументов читает stdin. Когда ты пишешь cat > notes.txt, shell:
- открывает (создаёт/обнуляет)
notes.txtна запись; - подключает его к stdout cat'а;
- cat ждёт ввода с клавиатуры, и каждая строка сразу падает в файл (Ctrl+D — конец ввода).
> выполняется shell'ом до запуска команды — поэтому файл создаётся даже если команда упадёт, и именно поэтому cat > file опасно: опечатка в имени стирает не тот файл. Проверяй, потом жми Enter.
Тот же трюк с heredoc (многострочный текст прямо в скрипте):
bash
cat > /etc/network/interfaces <<'EOF'
auto lo
iface lo inet loopback
auto eth0
iface eth0 inet static
address 192.168.100.11/24
gateway 192.168.100.1
EOF
# <<'EOF' с кавычками — внутри НЕ подставляются переменные (важно для конфигов!)
# <<EOF без кавычек — подстановка разрешенаЭтим приёмом я собирал /etc/network/interfaces на Alpine одной командой по SSH.
5. Пайпы |: конвейер обработки
bash
ip neigh | grep REACHABLE | wc -l # сколько живых соседей
cat /var/log/messages | grep -i dhcp # фильтр по логу
dmesg | tail -20 # последние 20 строкКаждая команда получает stdout предыдущей на свой stdin. Пайп не создаёт промежуточных файлов — данные текут в памяти. Дальше — tee, который «раздваивает» поток (видишь на экране И пишешь в файл):
bash
ping ya.ru | tee ping-report.txt # показывает пинг и пишет отчёт
echo "192.168.100.1 gw" | tee -a hosts # -a = дописать6. Переменные, условия, циклы — минимальный набор
bash
GW="192.168.100.1" # переменная, без пробелов вокруг =
ping -c1 -W2 "$GW" >/dev/null
if [ $? -eq 0 ]; then # $? — код выхода предыдущей команды
echo "$GW жив"
else
echo "$GW не отвечает"
fi
# короткая форма без if:
ping -c1 -W2 "$GW" >/dev/null && echo "жив" || echo "мёртв"
# цикл по списку (массовая проверка клиентов подсети):
for ip in 11 12 13 14 15; do
ping -c1 -W1 "192.168.100.$ip" >/dev/null && echo ".100.$ip OK" || echo ".100.$ip DOWN"
done
# цикл по файлу (например, список свитчей):
while read -r host; do
echo "=== $host ==="
ping -c1 -W2 "$host" >/dev/null || echo "$host недоступен"
done < switches.txt[ ... ] — это команда test (проверки: -f файл существует, -z строка пуста, -eq числа равны, = строки равны). [ "$a" = "$b" ] — пробелы вокруг скобок и = обязательны!
set -e в начале скрипта = «падать при любой ошибке» — двойственная штука: спасает от полуработающих скриптов, но требует явных || true там, где фейл допустим (пример из нашего create-chr.sh: virsh destroy chr 2>/dev/null || true).
7. sed: найти и заменить (регулярные выражения)
sed читает текст построчно и применяет команды. Королевская команда — замена:
bash
sed 's/старое/новое/' file.txt # заменить ПЕРВОЕ вхождение в каждой строке (вывод в stdout)
sed 's/старое/новое/g' file.txt # g — ВСЕ вхождения в строке
sed -i 's/старое/новое/g' file.txt # -i — править файл НА МЕСТЕ (in-place, бэкап потом не вспомнишь — сначала копия!)Синтаксис s/.../.../… — «s» = substitute. Между slash'ами: шаблон / замена / флаги.
Мини-словарь регулярных выражений (хватает на 90% задач)
| Шаблон | Значит |
|---|---|
. | любой один символ |
* | предыдущий символ/группа: 0 или много раз (192.* — «192.» и дальше что угодно) |
^ | начало строки; $ — конец строки |
[0-9] | любая цифра; [a-z] — любая маленькая буква |
\+ | один или больше (в sed пиши \+, в grep -E просто +) |
\( \) | скобки-«карманы»: пойманное потом достаётся как \1, \2… |
Примеры из реальной жизни наладчика
bash
# поменять IP шлюза в конфиге Alpine (делал так в лабе):
sed -i 's/100\.11/100\.12/' /etc/network/interfaces
# ^^ точки экранируем \. — иначе «.» = «любой символ»!
# выдернуть IP из вывода (карманы): ip -br a → «eth0 UP 192.168.100.11/24 …»
ip -br a show eth0 | sed -n 's/.* \([0-9.]*\)\/24.*/\1/p'
# -n + /p — печатать только строки, где сработала замена
# \([0-9.]*\) — карман «последовательность цифр и точек», \/24 — до маски /24
# закомментировать строку в конфиге:
sed -i 's|^gateway 192.168.100.1|#&|' /etc/network/interfaces
# ^ — начало строки; & — «всё, что нашлось» (полная замена на себя-же с #)
# заменить только на 3-й строке:
sed -i '3s/dhcp/static/' /etc/network/interfacesДва золотых правила sed:
- Сначала без
-i— смотри результат на stdout; убедился → добавляй-i. Опечатка в-i-команде над важным конфигом = «вчера всё работало». - Экранируй точки, когда ищешь IP:
192.168.1.1в regex — это «192<любой символ>168<любой>1<любой>1», а192\.168\.1\.1— строго IP.
sed vs grep vs awk (когда что)
- grep — отфильтровать строки по шаблону (
grep -v— наоборот, НЕ подходящие); - sed — изменить строки (замены, удаление строк
5d, вставка); - awk — посчитать/разобрать по колонкам (
awk '{print $1}'— первая колонка,awk '$3>100'— где третья колонка больше 100). Частая связка:awk '{print $2}' | sort | uniq -c | sort -rn— «частотная таблица чего угодно» (топ IP в логе!).
8. Собери всё вместе: боевой пример
Скрипт «утренний обход сети» — тот, что положат в портфолио:
bash
#!/bin/bash
# morning-check.sh — проверка доступности хостов из списка
set -euo pipefail # -e падать при ошибке, -u кричать на пустые переменные,
# pipefail считать упавшим пайп, если упал ЛЮБОЙ его элемент
LIST="${1:-hosts.txt}" # список хостов: первый аргумент или hosts.txt по умолчанию
REPORT="report-$(date +%H%M).txt"
echo "=== Обход сети $(date) ===" | tee "$REPORT"
while read -r host; do
[ -z "$host" ] && continue # пропустить пустые строки
ping -c2 -W2 "$host" >/dev/null 2>&1 \
&& echo "[ OK ] $host" | tee -a "$REPORT" \
|| echo "[FAIL] $host" | tee -a "$REPORT"
done < "$LIST"
echo "Готово: $REPORT"Запуск: chmod +x morning-check.sh && ./morning-check.sh. Каждый приём здесь ты уже знаешь: &&/||, tee, while read, 2>&1, параметр по умолчанию ${1:-...}.
9. Шпаргалка на полях
bash
cmd > f # перезаписать cmd >> f # дописать
cmd 2> f # ошибки в файл cmd 2>&1 | … # всё в пайп
cmd1 && cmd2 # cmd2 только если cmd1 ок
cmd1 || cmd2 # cmd2 только если cmd1 фейл
echo "$x" # всегда в кавычках!
sed -i 's/a/b/g' f # замена: сначала без -i!
grep -E 'пат(терн)?' f # -E расширенные regexПримеры скриптов с разбором каждой строки: ~/NetLab/create-chr.sh (вводил в &&/||, set -e, переменные), ~/NetLab/type-to-vm.sh (цикл по строке, case, функции), ~/NetLab/netlab-up.sh (цикл по списку VM).