Câu 1Cái gì đi vào $2 khi bạn chạy ./a.sh foo bar?
Shell Script - Tham số và mã thoát
Nhận các giá trị của ./a.sh foo bar bằng $1 $2 $@ $# $0, bổ sung giá trị mặc định bằng ${2:--}, kiểm tra $? và trả về thành công hay thất bại bằng exit 0 / exit 1 — viết và chạy một script thực dụng, minh họa trên terminal trong trình duyệt.
Nhận tham số — $1 / $2 / $0
Script có thể nhận giá trị khi bạn chạy nó.
Các giá trị bạn liệt kê sau lệnh, như ./a.sh foo bar, được gọi là tham số, và bên trong script $1 là tham số thứ nhất còn $2 là tham số thứ hai.
$0 là tên của chính script, $# là số lượng tham số được truyền, và $@ đại diện cho tất cả chúng gộp lại.
Với những thứ này, bạn có thể chạy script với đầu vào khác nhau mỗi lần thay vì với các giá trị cố định.
| Cú pháp | Ý nghĩa | Ví dụ |
|---|---|---|
$1 $2 | Tham số thứ nhất và thứ hai | echo "$1 then $2" |
$0 | Tên của chính script | echo "running $0" |
$# | Số lượng tham số được truyền | echo "argc=$#" |
$@ | Tất cả tham số gộp lại | echo "all: $@" |
$1 $2; $# cho biết số lượng và $@ là cả tập hợp.set -- foo bar # đặt tham số vị trí để minh họa
echo "1st: $1" # foo
echo "2nd: $2" # bar
echo "argc: $#" # 2
echo "all: $@" # foo bar
Bổ sung giá trị mặc định — ${1:-def}
Đôi khi không có tham số nào được truyền.
Nếu bạn viết ${1:-default}, default được dùng khi $1 chưa được đặt hoặc rỗng, còn giá trị đã cho được dùng khi có.
Điều này cho phép bạn viết một script theo tham số khi có, và chạy trên một mặc định an toàn khi không.
Kiểm tra $# cũng cho biết liệu số lượng tham số mong đợi đã tới chưa.
| Cú pháp | Ý nghĩa | Ví dụ |
|---|---|---|
${1:-def} | Dùng def khi $1 chưa được đặt | name=${1:-guest} |
${2:-def} | Dùng def khi $2 chưa được đặt | sep=${2:--} |
${2:--}, truyền giá trị thứ hai thì dùng nó, còn bỏ qua thì dùng mặc định -.set -- # tái hiện việc chạy không có tham số
echo "${1:-guest}" # chưa đặt, nên guest
set -- alice # giờ tham số thứ nhất đã được đặt
echo "${1:-guest}" # có giá trị, nên alice
Trả về thành công hay thất bại — $? và exit N
Khi một lệnh kết thúc, nó trả về một mã thoát, một số từ 0 đến 255.
Theo quy ước 0 nghĩa là thành công và bất cứ thứ gì khác 0 nghĩa là thất bại.
Bạn có thể đọc mã thoát của lệnh trước đó bằng $?.
Với grep nó là 0 khi tìm thấy và 1 khi không, nên giá trị thay đổi theo kết quả.
Từ bên trong một script, bạn đặt mã thoát một cách tường minh bằng exit N.
Trả về exit 0 cho thành công và exit 1 cho thất bại là quy ước phổ biến.
Bên gọi nhận giá trị này qua $? hoặc && || và có thể dùng nó để điều khiển, chẳng hạn chỉ đi tiếp khi thành công.
Nếu bạn bỏ exit, mã thoát của lệnh chạy cuối cùng được trả về nguyên dạng.
| Cú pháp | Ý nghĩa | Ví dụ |
|---|---|---|
$? | Mã thoát của lệnh trước đó | grep x f; echo $? |
exit N | Kết thúc script với mã thoát N | exit 1 |
exit 0 khi thành công và exit 1 khi thất bại, và bên gọi đọc kết quả bằng $?.printf 'apple\nbanana\n' > fruits.txt # tạo nguyên liệu
grep apple fruits.txt > /dev/null
echo "found? $?" # tìm thấy, nên 0
grep mango fruits.txt > /dev/null
echo "found? $?" # không thấy, nên 1
Xử lý lần lượt từng tham số — $@ và $#
Khi số lượng tham số không cố định, thay vì viết $1 $2 từng cái một, hãy lặp qua $@ bằng for để xử lý bao nhiêu tham số được truyền cũng được.
Dạng for x in "$@"; do … done lấy chúng từng cái một, và hiển thị số lượng bằng $# cho phép cùng một script xử lý bất kỳ số lượng tham số nào.
Đây là một mẫu phổ biến trong các công cụ xử lý nhiều tệp cùng lúc.
| Cú pháp | Ý nghĩa | Ví dụ |
|---|---|---|
"$@" | Truyền từng tham số một từ một (cho for; cần nháy kép) | for x in "$@"; do |
$# | Số lượng tham số được truyền | echo "count=$#" |
$#, rồi lấy từng tham số một bằng $@ trong vòng lặp for để xử lý chúng.set -- foo bar baz # đặt tham số vị trí để minh họa
echo "argc: $#" # 3
for x in "$@"; do
echo "- $x" # - foo / - bar / - baz
done
Kiểm tra kiến thức
Hãy trả lời từng câu hỏi một.
Câu 2Ý nghĩa đúng của ${1:-guest} là gì?
Câu 3Cách nào đọc mã thoát cho biết lệnh trước đó có thành công không?