+8

Tìm hiểu về exit code trong bash script

Chúng ta bắt đầu với một ví dụ đơn giản về một bash script:

#!/bin/bash

cd $my_photo/ex_first_girlfriend
rm *

Thật là dễ hiểu phải không, chỉ là vào thư mục ex_first_girlfriend và xoá tất cả quá khứ thôi, để còn dọn đường cho thư mục current_first_girlfriend nữa chứ (hoho).. ai lại không muốn là người đầu tiên =))

Run..

What the hợi?? Sao thư mục hiện tại lại mất hết files rồi.. biết bao tài liệu văn hoá chính trị quốc tế từ Liên Xô cho đến Mỹ, lại thêm cả Nhật mà mấy năm trời tích góp không cánh mà bay (khoc3).. thiên địa ơi, tại sao lại thế........

Nguyên nhân

Vì đó là một ngày xấu trời, xấu đến mức có câu lệnh cd thôi mà chiếc máy tính hàng hịn mới sắm của bạn cũng chạy lỗi. Vậy là thay vì xoá đi quá khứ về người ấy, bạn lại xoá hết cả files ở thư mục hiện tại =)).

"Vậy tôi phải làm sao để không phụ thuộc thời tiết?"

Hãy viết bash script một cách nghiêm chỉnh, và hãy tìm hiểu về exit code.

Exit code là gì

Trong hệ thống Unix và Linux, khi kết thúc thì một chương trình có thể trả lại giá trị cho process đã gọi nó. Giá trị đó được gọi là exit code, hay exit status. Thông thường thì 0 ứng với xử lý thành công, còn 1 trở lên ứng với xử lý thất bại.

Không ít dự án phải đụng đến script, nhưng không phải script nào cũng nhắc đến exit code. Dường như exit code dễ đến mức mà người ta cũng dễ quên sự tồn tại của nó. Bởi thế mà tình huống xoá nhầm files như ví dụ bên trên mới có thể xảy ra =)). Nếu bạn viết script để sử dụng automation tools hay monitoring tools, những chương trình này sẽ dựa vào status code được trả lại từ script để quyết định script đó đã được thực thi thành công hay không.

Ngay cả khi bạn không định nghĩa, exit code vẫn tồn tại trong script của bạn. Vì vậy, bạn cần định nghĩa các exit codes tốt nhất có thể để tránh các vấn đề phát sinh sau này (dance3)

Làm quen với exit code

Thử một ví dụ trên terminal:

⇒  true; echo $?
0
⇒  false; echo $?
1

2 câu lệnh truefalse ở trên chả làm gì cả ngoại trừ việc trả lại exit code =)). Điều tôi muốn các bạn chú ý ở đây là $? - biến môi trường được sử dụng để lưu trữ exit code của câu lệnh gần nhất được thực thi trước đó.

Thử với một bash file test.sh nào:

#!/bin/bash

touch /root/hidden_diary
echo created file

touch được sử dụng để tạo file mới, còn echo là gì thì chắc không cần giải thích =)).

⇒  ./test.sh
touch: Permission denied
create file
⇒  echo $?
0

Vậy là ta đang không có quyền root để thực hiện touch như thế, tuy nhiên exit code của bash file trên trả về vẫn là 0 (thành công) vì đấy là exit code của câu lệnh echo created file.

Xoá echo đi và các bạn sẽ thấy kết quả như mong muốn:

#!/bin/bash

touch /root/hidden_diary
⇒  ./test.sh
touch: Permission denied
⇒  echo $?
1

Sử dụng exit code

Bash file

Quay trở lại với ví dụ về touch ở trên, một cách pro hơn nhé (dance3)

#!/bin/bash

touch /root/hidden_diary 2> /dev/null

if [ $? -eq 0 ]
then
  echo "Yeahhh!!!"
else
  echo "Oh no, could not create file..." >&2
fi

Chạy thử nhé

⇒  ./test.sh
Oh no, could not create file...
⇒  echo $?
0

Vì câu lệnh touch không thực thi thành công, nên đã in ra error message mà ta mong muốn (yeah)

Ơ, có gì đó kỳ lạ ở đây?? Lỗi mà sao in kết quả trả về lại là 0 (khoc3)

OK, hãy để câu lệnh exit cứu rỗi cho bạn =)). Với exit, bạn có thể gán giá trị trả về cho từng tình huống khác nhau trong chương trình.

#!/bin/bash

touch /root/hidden_diary 2> /dev/null

if [ $? -eq 0 ]
then
  echo "Yeahhh!!!"
  exit 0
else
  echo "Oh no, could not create file..." >&2
  exit 1
fi
⇒  ./test.sh
Oh no, could not create file...
⇒  echo $?
1

(goodjob)

Command line

Hãy xem thử một pro thực thi bash file trên như thế nào:

⇒  ./test.sh && echo "I'm a pro" || (sudo ./test.sh && echo "I'm a pro." || echo "...")
Oh no, could not create file...
Yeahhh!!!
I'm a pro.

Vậy là ta đã tạo thành công hidden_diary trong thư mục /root/ (yeah).

Phương thức sử dụng nhiều commands như trên được gọi là list constructs trong bash. List contructs giúp bạn có thể nối các commands với nhau bằng các điều kiện đơn giản như && (AND) hay || (OR). Ở ví dụ trên, đầu tiên ./test.sh được thực thi, vì exit code lúc này là 1 nên phần trong ngoặc sẽ được thực thi kế tiếp. Do sudo ./test.sh thành công, trả lại 0 nên câu lệnh echo "I'm a pro." được gọi đến.

Sử dụng list constructs trong command line thực sự cho thấy tầm quan trọng của việc nắm vững kiến thức về exit code (thanks).

ANDOR là cái hợi gì thế ??

command1 && command2

Đây là AND, command2 được thực thi khi và chỉ khi command1 trả lại exit code bằng 0.

command1 || command2

Còn đây là OR, command2 được thực thi khi và chỉ khi command1 trả lại exit code khác 0.

Thử chút là hiểu ngay thoai:

⇒  true || echo "Happy New Year!!"
⇒  false || echo "Happy New Year!!"
Happy New Year
⇒  true && echo "Happy New Year!!"
Happy New Year
⇒  false && echo "Happy New Year!!"
⇒

This Is the End (2013) - 6.7/10 (IMDb)

Quay lại ví dụ đầu tiên và xoá ảnh trong thư mục ex_first_girlfriend thôi, để lâu nữa phát sinh issue khác ngoài ý muốn thì exit code cũng ko cứu nổi bạn đâu (haha)

#!/bin/bash

error_exit()
{
    echo "$1" 1>&2
    exit 1
}

if cd $my_photo/ex_first_girlfriend; then
    rm *
else
    error_exit "Cannot change directory!  Good luck."
fi

Ngon rồi thì mkdir $my_photo/current_first_girlfriend thôi nào (dance3).


All Rights Reserved

Viblo
Let's register a Viblo Account to get more interesting posts.