Học bằng cách đọc theo thứ tự

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ĩaVí dụ
$1 $2Tham số thứ nhất và thứ haiecho "$1 then $2"
$0Tên của chính scriptecho "running $0"
$#Số lượng tham số được truyềnecho "argc=$#"
$@Tất cả tham số gộp lạiecho "all: $@"
Cách tham số được ánh xạ
./a.sh foo bar$1 = foo$2 = bar$# = 2$@ = foo barthứ 1thứ 2số lượngtất cả
Các giá trị bạn truyền đi vào $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

Tạo một script nhận các giá trị làm tham số và in chúng ra nguyên dạng.

① Mở args.sh bằng vi args.sh, nhấn i để vào insert mode, và viết #!/bin/sh ở dòng đầu.

② Viết code in tham số thứ nhất ($1), thứ hai ($2), số lượng ($#), tất cả tham số ($@), và tên script ($0).

③ Nhấn Esc, lưu bằng :wq, rồi cấp quyền thực thi cho tệp.

④ Chạy nó dưới dạng ./args.sh foo bar với hai tham số và kiểm tra giá trị nào đi vào biến nào. Nếu bí, bạn có thể sao chép nội dung từ bảng đáp án và dán vào insert mode của vi. (Nếu chạy đúng, phần giải thích sẽ hiện ra.)

Linux console
0 / 3 đã hoàn thành
Loading Linux Terminal...

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ĩaVí dụ
${1:-def}Dùng def khi $1 chưa được đặtname=${1:-guest}
${2:-def}Dùng def khi $2 chưa được đặtsep=${2:--}
Cách giá trị mặc định được bổ sung
sep=${2:--}$2 = barsep = bar$2 rỗngsep = - (mặc định)nếu cónếu bỏNhư đã truyềnDùng mặc định
Với ${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

Tạo một script nhận một dấu phân tách làm tham số và dùng giá trị mặc định khi nó bị bỏ qua.

① Mở format.sh bằng vi format.sh, nhấn i để vào insert mode, và viết #!/bin/sh ở dòng đầu.

② Nhận tham số thứ nhất làm tên đối tượng và tham số thứ hai làm dấu phân tách, nhưng viết bằng ${2:-...} để một mặc định (ví dụ -) được dùng khi thiếu tham số thứ hai, rồi in tên đối tượng và dấu phân tách.

③ Nhấn Esc, lưu bằng :wq, rồi cấp quyền thực thi cho tệp.

④ Trước tiên chạy nó dưới dạng ./format.sh foo, bỏ qua tham số thứ hai, và kiểm tra rằng dấu phân tách quay về mặc định. Nếu bí, bạn có thể sao chép nội dung từ bảng đáp án và dán vào insert mode của vi.

Linux console
0 / 3 đã hoàn thành
Loading Linux Terminal...

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ĩaVí dụ
$?Mã thoát của lệnh trước đógrep x f; echo $?
exit NKết thúc script với mã thoát Nexit 1
Luồng của mã thoát
Tiến trình thành côngexit 0$? = 0Tiến trình thất bạiexit 1$? = 1trả vềđọctrả vềđọcThành côngThất bại
Một script trả về 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

Tạo một script tìm trong một tệp một từ được cho làm tham số và trả về mã thoát dựa trên kết quả.

① Mở search.sh bằng vi search.sh, nhấn i để vào insert mode, và viết #!/bin/sh ở dòng đầu.

② Trong script, tạo một tệp nguyên liệu và tìm trong đó từ nhận được làm tham số thứ nhất. Viết code in một thông điệp thành công và trả về exit 0 khi tìm thấy, hoặc in một thông điệp thất bại và trả về exit 1 khi không.

③ Nhấn Esc, lưu bằng :wq, rồi cấp quyền thực thi cho tệp.

④ Chạy nó dưới dạng ./search.sh foo bar, rồi kiểm tra mã thoát bằng echo $?. Nếu bí, bạn có thể sao chép nội dung từ bảng đáp án và dán vào insert mode của vi.

Linux console
0 / 3 đã hoàn thành
Loading Linux Terminal...

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ĩaVí 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ềnecho "count=$#"
Lặp qua tất cả tham số
./a.sh foo bar baz$# = 3$@ = foo bar bazfor x in "$@"- foo- bar- bazsố lượngtất cảtừng cái mộtinlặp bằng for
Lấy số lượng bằng $#, 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

Tạo một script xử lý từng tham số được truyền một cái một và cũng hiển thị số lượng.

① Mở list.sh bằng vi list.sh, nhấn i để vào insert mode, và viết #!/bin/sh ở dòng đầu.

② In số lượng tham số bằng $#, rồi lấy từng cái lần lượt bằng $@ trong vòng lặp for và in mỗi tham số trên một dòng riêng.

③ Nhấn Esc, lưu bằng :wq, rồi cấp quyền thực thi cho tệp.

④ Chạy nó dưới dạng ./list.sh foo bar baz với ba tham số và kiểm tra rằng số lượng và từng tham số in ra theo thứ tự. Nếu bí, bạn có thể sao chép nội dung từ bảng đáp án và dán vào insert mode của vi.

Linux console
0 / 3 đã hoàn thành
Loading Linux Terminal...
QUIZ

Kiểm tra kiến thức

Hãy trả lời từng câu hỏi một.

Câu 1Cái gì đi vào $2 khi bạn chạy ./a.sh foo bar?

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?