Tarkibga o'tish

Exit kodlar va xatolarni qayta ishlash

return, exit 1 va systemctl is-active --quiet kabi buyruqlar oldingi maqolalarda bir necha marta uchradi va ularning hammasi bitta umumiy mexanizmga — exit kodga tayanadi. Bu maqola shu mexanizmni to'liq ochib beradi va Bash skriptni "ishlayotganga o'xshaydi" darajasidan "xato yuz berganda to'g'ri to'xtaydi va bu haqda xabar beradi" darajasiga ko'taradi. Bu farq, ayniqsa, keyingi modulda yoziladigan production skriptlar uchun muhim.

Nimalarni o'rganasiz

Bu maqola oxirida siz quyidagilarni qila olasiz:

  • exit kod nima ekanini tushuntirish va uni $? orqali o'qish;
  • exit yordamida skriptni o'z xato kodi bilan to'xtatish;
  • && va || bilan keyingi amalni oldingi buyruq natijasiga bog'lash;
  • set -e, set -u, set -o pipefail ning har biri nima qilishini va qachon xavfli bo'lishi mumkinligini tushuntirish;
  • skript tugaganda yoki signal olganda trap bilan tozalash ishlarini bajarish.

Exit kod nima

Linux’da ishga tushgan har bir buyruq — muvaffaqiyatli tugaydimi yoki yo'qmi — exit kod qaytaradi: 0 dan 255 gacha bo'lgan butun son. Qat’iy kelishuvga ko'ra:

  • 0 — muvaffaqiyat;
  • 1–255 — muvaffaqiyatsizlik. Aniq raqam ba’zan xato turini bildiradi (bu buyruqdan buyruqqa farq qiladi).

Eng oxirgi bajarilgan buyruqning exit kodi maxsus $? o'zgaruvchisida saqlanadi:

ls /etc/passwd
echo "Exit code: $?"
/etc/passwd
Exit code: 0
ls /etc/nofile
echo "Exit code: $?"
ls: cannot access '/etc/nofile': No such file or directory
Exit code: 2

$? faqat bevosita oldingi buyruqqa tegishli. Agar oraliqda boshqa biror buyruq (hatto echo) bajarilsa, $? o'sha buyruqning kodiga almashadi. Shuning uchun natijani darhol tekshirish yoki alohida o'zgaruvchiga saqlash kerak:

tar -czf /backup/data.tar.gz /data
status=$?

if [ "$status" -ne 0 ]; then
    echo "Backup failed (code: $status)"
fi

Skriptni o'z exit kodi bilan to'xtatish: exit

Skript ichidagi exit buyrug'i uni darhol to'xtatadi va berilgan sonni skriptning yakuniy exit kodiga aylantiradi:

#!/bin/bash

if [ -z "$1" ]; then
    echo "Error: an argument is required. Usage: $0 <file>" >&2
    exit 1
fi

echo "File: $1"

Agar exit yozilmasa, skript oxirgi buyruqning exit kodi bilan tugaydi. Bu ko'pincha noaniq bo'ladi va chaqiruvchiga (masalan, cron yoki boshqa skriptga) muvaffaqiyat yoki muvaffaqiyatsizlikni to'g'ri aniqlashga xalaqit berishi mumkin. Shuning uchun har bir muhim chiqish nuqtasida exit ni aniq yozish tavsiya etiladi: muvaffaqiyat uchun exit 0, turli muvaffaqiyatsizlik holatlari uchun boshqa raqamlar.

Note

>&2 xabarni standart chiqish (stdout) o'rniga standart xatolar oqimiga (stderr) yo'naltiradi. Bu xato xabarlarini muvaffaqiyatli chiqishdan ajratish uchun muhim odat: keyinchalik skript chiqishi pipe orqali boshqa buyruqqa uzatilganda yoki faylga yozilganda, xato xabarlari haqiqiy natija bilan aralashib ketmaydi.

Exit kodlarni kelishuvga moslashtirish

Yagona qat’iy standart yo'q, lekin keng amal qilinadigan kelishuv mavjud:

Kod Ma’nosi
0 muvaffaqiyat
1 umumiy xato
2 noto'g'ri foydalanish (masalan, argument yetishmaydi)
126 fayl topildi, lekin uni bajarib bo'lmadi (masalan, ruxsat yo'q)
127 buyruq topilmadi
128+N N signali bilan to'xtatilgan (masalan, 130 = 128 + 2, ya’ni Ctrl+C / SIGINT)

Bir nechta turdagi xato yuz berishi mumkin bo'lgan skriptda har biriga alohida kod berish chaqiruvchiga (yoki monitoring tizimiga) aynan nima noto'g'ri ketganini bilishga yordam beradi. Bu yondashuv Healthcheck skripti loyihasida bevosita qo'llaniladi, chunki monitoring tizimlari turli exit kodlarni ko'pincha turlicha talqin qiladi (masalan, Nagios uslubidagi tekshiruvlarda 0 = OK, 1 = WARNING, 2 = CRITICAL).

&& va ||: keyingi amalni exit kodga bog'lash

&& — keyingi buyruqni faqat oldingisi muvaffaqiyatli tugaganda (exit kod 0) bajaradi:

mkdir -p /backup/2026-07-26 && tar -czf /backup/2026-07-26/data.tar.gz /data

|| — keyingi buyruqni faqat oldingisi muvaffaqiyatsiz tugaganda (0 dan boshqa istalgan exit kod) bajaradi:

tar -czf /backup/data.tar.gz /data || echo "Backup failed" >&2

Ikkalasi birgalikda "muvaffaqiyat bo'lsa X, aks holda Y" shablonini ifodalaydi:

tar -czf /backup/data.tar.gz /data && echo "Backup OK" || echo "Backup failed" >&2

Warning

Bu uch qismli shablon (A && B || C) ehtiyotkorlik talab qiladi: agar B ham muvaffaqiyatsiz tugasa (masalan, echo ning o'zi juda kam hollarda xato beradi, lekin nazariy jihatdan bu mumkin), C ham bajariladi. Bu chalkash natijaga olib keladi. Murakkab mantiq uchun oddiy if/else aniqroq va xavfsizroq.

set -e, set -u, set -o pipefail: xatolarni qat’iyroq qayta ishlash

Standart holatda Bash skript xatodan keyin ham ishlashda davom etadi. Masalan, cd muvaffaqiyatsiz tugasa ham, keyingi qatordagi rm -rf * joriy (noto'g'ri) katalogda baribir bajariladi. Bunga yo'l qo'ymaslikka uchta sozlama yordam beradi:

set -e

Agar biror buyruq noldan farqli exit kod bilan tugasa, skript darhol to'xtaydi (agar buyruq if/while sharti sifatida yoki &&/|| ichida ishlatilmagan bo'lsa).

set -u

Agar e’lon qilinmagan (yoki qiymat berilmagan) o'zgaruvchi ishlatilsa, skript xato bilan to'xtaydi. Bu noto'g'ri yozilgan o'zgaruvchi nomini ($FILE o'rniga $FIEL) darhol fosh qiladi.

set -o pipefail

Agar pipeline’dagi (cmd1 | cmd2) istalgan buyruq muvaffaqiyatsiz tugasa, butun pipeline muvaffaqiyatsiz hisoblanadi. Standart holatda Bash pipeline’da faqat oxirgi buyruqning exit kodiga qaraydi. Bu shuni anglatadiki, masalan, cat missing_file.txt | grep pattern da cat muvaffaqiyatsiz tugasa ham, agar grep "topilmadi" ni o'zining muvaffaqiyatsizligi sifatida qaytarsa, butun pipeline yolg'ondan muvaffaqiyatli ko'rinishi mumkin.

Uchalasini birga ishlatish keng tarqalgan amaliyot. Ular ko'pincha skript boshida bitta qatorda yoziladi:

#!/bin/bash
set -euo pipefail
#!/bin/bash
set -euo pipefail

SOURCE_DIR="/data"
BACKUP_DIR="/backup"

tar -czf "${BACKUP_DIR}/data.tar.gz" "$SOURCE_DIR"
echo "Backup completed successfully"

Agar SOURCE_DIR yoki BACKUP_DIR mavjud bo'lmasa yoki tar biror sabab bilan muvaffaqiyatsiz tugasa, skript yolg'on "Backup completed successfully" xabarini chiqarmasdan darhol to'xtaydi.

Danger

set -e hamma holatlarni qamrab olmaydi va ba’zan skriptni kutilmagan joyda to'xtatishi mumkin. Masalan, if failing_command; then ichida testning muvaffaqiyatsiz tugashi kutilgan holat bo'lsa, set -e odatda buni to'g'ri qayta ishlaydi. Lekin funksiya ichidagi ba’zi murakkabroq holatlarda (masalan, command substitution ichida) u kutilganidek ishlamasligi mumkin. Shuning uchun set -euo pipefail "sehrli yechim" emas: u xatolarni balandroq ovozda bildiradi, lekin muhim amaldan (masalan, faylni o'chirishdan) keyin aniq tekshiruv baribir tavsiya etiladi. Production skriptni joriy qilishdan oldin uni har doim lab muhitida, xato holatlarini ataylab yuzaga keltirib sinab ko'ring.

trap: chiqishda yoki signal kelganda tozalash

Skript ishlayotganda vaqtinchalik fayl yaratishi yoki lock qo'yishi mumkin. Agar skript kutilmaganda to'xtasa (xato yoki foydalanuvchi Ctrl+C bosgani sababli), o'sha vaqtinchalik holat qolib ketishi mumkin. trap ma’lum signal kelganda yoki skript tugaganda berilgan buyruq/funksiyani avtomatik bajarish imkonini beradi:

#!/bin/bash
set -euo pipefail

LOCK_FILE="/tmp/backup.lock"

cleanup() {
    rm -f "$LOCK_FILE"
    echo "Cleanup complete"
}

trap cleanup EXIT

touch "$LOCK_FILE"
echo "Working..."
sleep 5
echo "Done"
Working...
Done
Cleanup complete

EXIT — maxsus psevdo-signal. U skript qanday tugashidan qat’i nazar (muvaffaqiyatli, xato bilan yoki exit orqali) ishga tushadi. Vaqtinchalik fayllarni tozalash yoki lock’ni bo'shatish uchun bu eng ishonchli joy, chunki skript set -e sababli kutilmagan qatorda to'xtasa ham u bajariladi.

Uni signal nomlari bilan ham ishlatish mumkin. Masalan, foydalanuvchi Ctrl+C (SIGINT) bosganda maxsus xabar chiqarish:

trap 'echo "Script stopped by the user"; cleanup; exit 130' SIGINT

Amaliy vaziyat: xavfsiz backup skripti — xatoni oldindan aniqlash

Vazifa: manba katalog mavjudligini oldindan tekshirish, faqat shundan keyin uni arxivlash va xato haqida aniq exit kod bilan xabar berish.

#!/bin/bash
set -euo pipefail

SOURCE_DIR="${1:-}"
BACKUP_DIR="/backup"

if [ -z "$SOURCE_DIR" ]; then
    echo "Error: no source directory given. Usage: $0 <directory>" >&2
    exit 2
fi

if [ ! -d "$SOURCE_DIR" ]; then
    echo "Error: directory '$SOURCE_DIR' not found" >&2
    exit 1
fi

mkdir -p "$BACKUP_DIR"

archive_name="${BACKUP_DIR}/$(basename "$SOURCE_DIR")-$(date +%Y%m%d).tar.gz"

if tar -czf "$archive_name" "$SOURCE_DIR"; then
    echo "Backup successful: $archive_name"
    exit 0
else
    echo "Error: archiving failed" >&2
    exit 1
fi
./safe_backup.sh /data
echo "Script exit code: $?"
Backup successful: /backup/data-20260726.tar.gz
Script exit code: 0

${1:-} — parameter expansion sintaksisi: agar $1 berilmagan bo'lsa, u xato o'rniga bo'sh satr qaytaradi. Bu set -u yoqilgan holatda $1 yo'qligi xatoga sabab bo'lmasligi uchun kerak. Har bir mumkin bo'lgan muvaffaqiyatsizlik holati (argument yo'q, katalog yo'q, tar muvaffaqiyatsiz tugadi) alohida tekshiriladi va mos kod bilan toza yakunlanadi. Bu skript cron orqali ishga tushirilganda yoki boshqa skriptdan chaqirilganda muvaffaqiyat yoki muvaffaqiyatsizlikni ishonchli aniqlash imkonini beradi.

Keng tarqalgan xatolar

$? ni juda kech tekshirish

tar -czf backup.tar.gz /data
echo "Started"
if [ $? -ne 0 ]; then

Bu yerda $? allaqachon tar natijasiga emas, echo ning exit kodiga (deyarli har doim 0) almashgan. $? ni buyruqdan darhol keyin o'qing yoki natijani o'zgaruvchiga saqlang.

set -e ga ishonib, muhim amaldan keyin baribir tekshirmaslik

set -e ko'p holatlarni qamrab oladi, lekin funksiya ichida yoki &&/|| zanjirining qismi sifatida ishlatilgan buyruq ba’zan skriptni kutilganidek to'xtatmasligi mumkin. Faylni o'chirish yoki ma’lumotlar bazasiga yozish kabi qaytarib bo'lmaydigan amallardan keyin har doim aniq if/exit kod tekshiruvini qoldiring.

Xato xabarlarini stdout ga yozish

echo "Error: file not found"

Bu xabar oddiy chiqish bilan bir oqimga tushadi. Agar skript chiqishi boshqa dasturga (masalan, monitoring tizimiga) uzatilsa, muvaffaqiyat va xato xabarlari ajralmay qoladi. To'g'risi: echo "Error: ..." >&2.

trap ni skript oxiriga, "hech qachon yetib borilmaydigan" joyga qo'yish

Tozalashni talab qiladigan resurs (vaqtinchalik fayl, lock) yaratilgandan keyin trap ni imkon qadar tezroq o'rnating. Agar trap skript oxirida yozilgan bo'lsa-yu, xato skriptni yarim yo'lda to'xtatsa, trap ning o'zi hech qachon ishga tushmaydi.

Mashqlar

  1. safe_backup.sh ni set -euo pipefail siz ishga tushiring va uni ataylab mavjud bo'lmagan katalog bilan chaqiring. So'ng set -euo pipefail yoqilgan holat bilan taqqoslang va natijadagi farqni tushuntiring.
  2. trap cleanup EXIT yordamida vaqtinchalik faylni ishonchli o'chiradigan kichik skript yozing. Uni ham oddiy chiqish, ham kill -TERM bilan sinab ko'ring va ikkala holatda ham tozalash ishlashini tasdiqlang.
  3. Exit kodlar jadvalidan foydalanib, ikki turdagi xatoni (argument yo'qligi va fayl yo'qligi) alohida kodlar bilan qaytaradigan skript yozing va har birini echo "$?" bilan tasdiqlang.
  4. false | true ning $? qiymatini set -o pipefail yoqilgan va o'chirilgan holatlarda taqqoslang.

Xulosa

Exit kod — har qanday buyruq yoki skript uchun muvaffaqiyat yoki muvaffaqiyatsizlikni ifodalaydigan universal til. $?, exit va &&/|| shu holatni o'qish va unga qarab harakat qilish imkonini beradi. set -euo pipefail Bash’ning standart "davom etaver" xatti-harakatini xatolarga sezgir qiladi, trap esa skript qanday tugashidan qat’i nazar tozalashni kafolatlaydi. Bu vositalar bilan endi modulning amaliy qismiga o'tish mumkin — Backup skripti, Healthcheck skripti va Log tozalash skripti loyihalari oldingi barcha mavzularni (o'zgaruvchilar, shartlar, sikllar, funksiyalar, exit kodlar) bitta ishlaydigan production skriptga birlashtiradi.

Manbalar