Gymterview
junior

Как писать bash-скрипты?

Bash-скрипт — это текстовый файл с последовательностью команд, которые интерпретатор bash выполняет как программу. Скрипты автоматизируют повторяющиеся задачи: сборку, деплой, мониторинг, обработку логов.

Создание и запуск

Пример
# Первая строка — shebang (указывает интерпретатор)
#!/bin/bash

# Более переносимый вариант (ищет bash через PATH)
#!/usr/bin/env bash

# Сделать скрипт исполняемым и запустить
chmod +x script.sh
./script.sh

# Или запустить через интерпретатор (chmod не нужен)
bash script.sh

Переменные

Пример
#!/bin/bash
name="World"                     # Без пробелов вокруг '='!
echo "Hello, $name!"
echo "Hello, ${name}!"          # Фигурные скобки для явности

# Результат команды в переменную
current_date=$(date +%Y-%m-%d)
files_count=$(ls | wc -l)

# Аргументы скрипта
echo "Script name: $0"
echo "First argument: $1"
echo "Second argument: $2"
echo "All arguments: $@"
echo "Number of arguments: $#"

# Чтение ввода от пользователя
read -p "Enter your name: " username
echo "Hello, $username!"

Условия (if/elif/else)

Пример
#!/bin/bash
if [ -f "pom.xml" ]; then
    echo "Maven project detected"
elif [ -f "build.gradle" ]; then
    echo "Gradle project detected"
else
    echo "Unknown project type"
fi

# Проверка аргументов
if [ $# -eq 0 ]; then
    echo "Usage: $0 <environment>"
    exit 1
fi

Циклы

Примеры циклов for, while, чтение файла
#!/bin/bash
# Цикл for
for file in *.java; do
    echo "Processing: $file"
done

# For с диапазоном
for i in {1..10}; do
    echo "Iteration $i"
done

# C-style for
for ((i=0; i<5; i++)); do
    echo "$i"
done

# While
count=0
while [ $count -lt 5 ]; do
    echo "Count: $count"
    ((count++))
done

# Чтение файла построчно
while IFS= read -r line; do
    echo "Line: $line"
done < file.txt

Функции

Пример
#!/bin/bash
build_project() {
    local project_dir="$1"           # local — локальная переменная
    local profile="${2:-dev}"        # Значение по умолчанию — "dev"

    echo "Building $project_dir with profile $profile..."
    cd "$project_dir" || return 1
    mvn clean package -P"$profile"
    return $?                        # Вернуть код возврата mvn
}

# Вызов функции
build_project "/opt/myapp" "production"
if [ $? -eq 0 ]; then
    echo "Build successful!"
else
    echo "Build failed!"
fi

Полный пример — скрипт деплоя

deploy.sh — скрипт сборки и деплоя
#!/bin/bash
set -euo pipefail   # Строгий режим: ошибки, неопределённые переменные, пайпы

APP_NAME="myapp"
JAR_FILE="target/${APP_NAME}.jar"
REMOTE_HOST="production"
REMOTE_DIR="/opt/${APP_NAME}"

log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1"
}

log "Building project..."
mvn clean package -DskipTests || { log "Build failed!"; exit 1; }

log "Deploying to ${REMOTE_HOST}..."
rsync -avz "$JAR_FILE" "${REMOTE_HOST}:${REMOTE_DIR}/"

log "Restarting application..."
ssh "$REMOTE_HOST" "sudo systemctl restart ${APP_NAME}"

log "Deployment complete!"

Вывод

Минимальный набор для продуктивного скриптинга: shebang, set -euo pipefail, переменные, условия, циклы, функции с local. Всё остальное — комбинация этих элементов.

На собеседовании: обязательно упомяните set -euo pipefail как первую строку после shebang — это показывает зрелый подход к скриптингу. Объясните, зачем нужен каждый флаг: -e останавливает при ошибке, -u ловит опечатки в именах переменных, -o pipefail не маскирует ошибки в пайпах.