jvinhit//lab

Search posts

Type to search across journal entries.

navigate open esc close

Bash & Shell Scripting · Part 1 — The Shell, the Shebang & Your First Script

Start scripting from zero: what a shell really is, bash vs sh, the shebang line, making a script executable, the three ways to run it, echo vs printf, and exit codes — bilingual, with exercises.

Đây là Phần 1 của series 10 bài đưa bạn từ “copy-paste lệnh” đến viết shell script chắc chắn, mức production. Mỗi phần đều thực hành, có ví dụ thật và bài tập.

Hết series, bạn sẽ đọc, viết, và debug shell script một cách tự tin.


Shell là gì?

Một shell là chương trình đọc lệnh của bạn rồi nhờ hệ điều hành chạy chúng. Khi bạn mở terminal, một shell đang chờ ở dấu nhắc.

Bash là shell phổ biến nhất trên Linux và là mục tiêu scripting mặc định gần như mọi nơi.

You type ls -l /tmp Shell (bash) parse · expand fork + exec new process Kernel runs /bin/ls exit code flows back ← ($? = 0 means success)
The shell parses your line, expands it, then fork+exec hands the real work to the kernel; an exit code comes back

Có hai cách bạn dùng shell:

  • Tương tác: gõ một lệnh, Enter, xem kết quả.
  • Kịch bản: bỏ nhiều lệnh vào một file rồi chạy cả loạt.

Series này nói về cách thứ hai.


bash vs sh — vì sao quan trọng

sh là shell POSIX gốc, tối giản. bash là tập cha với nhiều tính năng hơn hẳn.

Trên nhiều hệ thống /bin/sh không phải bash — có thể là dash. Một script chạy được với bash có thể vỡ dưới sh. Vậy luôn nói rõ bạn nhắm shell nào.

Quy tắc: nếu bạn dùng tính năng bash, hãy khai báo bash ở shebang và chạy bằng bash.


Dòng shebang

Dòng đầu của script cho hệ thống biết trình thông dịch nào sẽ chạy file. Nó bắt đầu bằng #! — gọi là shebang.

#!/usr/bin/env bash

Vì sao dùng /usr/bin/env bash thay vì /bin/bash? Vì env tìm bash trên PATH của người dùng, nên script chạy được dù bash nằm ở /bin, /usr/bin, hay path của Homebrew.


Script đầu tiên của bạn

Tạo file hello.sh:

#!/usr/bin/env bash
# hello.sh — my first script
# Lines starting with # are comments (the shebang is the one exception).

echo "Hello from a script!"
echo "Today is: $(date +%Y-%m-%d)"

Để ý các comment #: mọi thứ sau # trên một dòng đều bị bash bỏ qua. Dùng chúng để giải thích vì sao, không phải cái gì.


Cho phép chạy & chạy script

File .sh mới chỉ là text. Để chạy như một chương trình, bạn cấp quyền execute:

chmod +x hello.sh   # add the execute bit
./hello.sh          # run it (note the ./)

Cái ./ quan trọng: nghĩa là “file trong thư mục này”. Không có nó, shell chỉ tìm trong PATH và sẽ không thấy file của bạn.

Ba cách chạy script

LệnhChuyện gì xảy ra
./hello.shDùng shebang; cần quyền execute
bash hello.shÉp bash; bỏ qua shebang & quyền execute
source hello.sh (or . hello.sh)Chạy trong shell hiện tại — biến còn lại sau khi chạy xong

Bẫy: ./hello.shbash hello.sh chạy trong shell con, nên biến chúng đặt sẽ biến mất khi xong. Chỉ source giữ lại.


echo vs printf

echo in một dòng — nhanh và ổn cho output đơn giản. printf chính xác và portable hơn khi cần định dạng:

echo "Name: Alice"

printf "%-10s %s\n" "Name:" "Alice"   # control width
printf "Progress: %d%%\n" 80          # Progress: 80%

Ưu tiên printf cho mọi thứ cần định dạng hoặc nơi flag của echo khác nhau giữa các hệ thống.


Exit code — nhịp tim của scripting

Mỗi lệnh trả về một con số khi kết thúc: 0 là thành công, khác 0 là thất bại. Bạn đọc nó từ biến đặc biệt $?:

ls /tmp
echo "$?"        # 0 — it worked

ls /nope 2>/dev/null
echo "$?"        # non-zero — it failed

Đây là nền tảng cho if, &&, ||, và xử lý lỗi ở các phần sau. Script của bạn cũng có thể trả về code:

exit 0   # success
exit 1   # generic failure

Lỗi người mới hay mắc

  • Quên chmod +x rồi bối rối vì sao ./script.sh báo “Permission denied”.
  • Quên ./ và thấy “command not found”.
  • Soạn trên Windows và lưu kiểu xuống dòng CRLF — bash nghẹn với \r. Dùng LF.
  • Tưởng /bin/sh là bash.

Bài tập

Thử từng bài trước khi mở lời giải.

  1. Viết script whoami-now.sh in username và giờ hiện tại, rồi thoát với code 0.
  2. Chạy cùng script theo ba cách và giải thích khác biệt với một biến bạn đặt bên trong.
  3. Cố ý làm một lệnh thất bại rồi in exit code của nó.
Lời giải
#!/usr/bin/env bash
# whoami-now.sh
echo "User: $(whoami)"
printf "Time: %s\n" "$(date +%H:%M:%S)"
exit 0
chmod +x whoami-now.sh
./whoami-now.sh          # child shell (shebang)
bash whoami-now.sh       # child shell (forced bash)
source whoami-now.sh     # current shell — any variable set inside survives here

# Exercise 3:
grep something /no/such/file
echo "exit code: $?"     # prints a non-zero number

source chạy các dòng trong shell hiện tại, nên biến gán trong script vẫn còn sau đó. ./bash chạy shell con, nên các biến đó biến mất.


Điều cốt lõi

Một script chỉ là các lệnh trong file, được chỉ định interpreter qua shebang, đánh dấu executable, và chạy bằng ./. Theo dõi exit code — nó điều khiển mọi thứ phía sau.