105.2 Bài 2
Chứng chỉ: |
LPIC-1 |
---|---|
Phiên bản: |
5.0 |
Chủ đề: |
105 Vỏ và Tệp lệnh Vỏ |
Mục tiêu: |
105.2 Tùy chỉnh hoặc viết các Tệp lệnh đơn giản |
Bài: |
2 trên 2 |
Giới thiệu
Tệp lệnh Vỏ thường được sử dụng nhằm mục đích tự động hóa các hoạt động liên quan đến tệp và thư mục - chính là các hoạt động có thể được thực hiện thủ công tại dòng lệnh. Tuy nhiên, phạm vi hoạt động của các tệp lệnh vỏ không bị giới hạn ở tài liệu của người dùng vì việc cấu hình và tương tác với nhiều khía cạnh của hệ điều hành Linux cũng được thực hiện thông qua các tệp lệnh.
Vỏ Bash có cung cấp nhiều lệnh tích hợp sẵn hữu ích để viết các tệp lệnh vỏ, nhưng toàn bộ sức mạnh của các tệp lệnh này phụ thuộc vào sự kết hợp của các lệnh tích hợp sẵn của Bash với các tiện ích dòng lệnh có sẵn trên hệ thống Linux.
Kiểm tra mở rộng
Bash là một ngôn ngữ tệp lệnh chủ yếu được định hướng để làm việc với các tệp. Vì vậy, lệnh test
tích hợp sẵn của Bash có nhiều tùy chọn để đánh giá đặc tính của các đối tượng hệ thống tệp (về cơ bản là tệp và thư mục). Các phiên kiểm tra tập trung vào tệp và thư mục thực sự rất hữu ích: chẳng hạn như để xác minh xem các tệp và thư mục cần thiết để thực hiện một tác vụ cụ thể có hiện diện và có thể đọc được hay không. Sau đó, cùng với cấu trúc có điều kiện if, một chuối hành động thích hợp sẽ được thực thi nếu kiểm tra thành công.
Lệnh test
có thể đánh giá các biểu thức bằng hai cú pháp khác nhau: các biểu thức kiểm tra có thể được đưa ra làm đối số cho lệnh test
hoặc có thể được đặt bên trong dấu ngoặc vuông (lệnh test
được thực hiện ngầm). Do đó, việc kiểm tra để đánh giá xem /etc
có phải là một thư mục hợp lệ hay không có thể được viết dưới dạng test -d /etc
hoặc [ -d /etc]
:
$ test -d /etc $ echo $? 0 $ [ -d /etc ] $ echo $? 0
Như được xác nhận bởi mã trạng thái thoát trong biến đặc biệt $?
— một giá trị 0 có nghĩa là đã kiểm tra thành công — cả hai mẫu đều đánh giá /etc
là một thư mục hợp lệ. Giả sử đường dẫn đến một tệp hoặc thư mục được lưu trữ trong biến $VAR
, các biểu thức sau có thể được sử dụng làm đối số cho test
hoặc bên trong dấu ngoặc vuông:
-a "$VAR"
-
Đánh giá xem đường dẫn trong
VAR
có tồn tại trong hệ thống tệp hay không và đó có phải là một tệp hay không. -b "$VAR"
-
Đánh giá xem đường dẫn trong
VAR
có phải là một tệp khối đặc biệt hay không. -c "$VAR"
-
Đánh giá xem đường dẫn trong
VAR
có phải là một tệp ký tự đặc biệt hay không. -d "$VAR"
-
Đánh giá xem đường dẫn trong
VAR
có phải là một thư mục hay không. -e "$VAR"
-
Đánh giá xem đường dẫn trong
VAR
có tồn tại trong hệ thống tệp hay không. -f "$VAR"
-
Đánh giá xem đường dẫn trong
VAR
có tồn tại hay không và đó có phải là một tệp thông thường hay không. -g "$VAR"
-
Đánh giá xem đường dẫn trong
VAR
có quyền SGID hay không. -h "$VAR"
-
Đánh giá xem đường dẫn trong
VAR
có phải là liên kết tượng trưng hay không. -L "$VAR"
-
Đánh giá xem đường dẫn trong
VAR
có phải là liên kết tượng trưng hay không (như-h
). -k "$VAR"
-
Đánh giá xem đường dẫn trong
VAR
có quyền bit dính hay không. -p "$VAR"
-
Đánh giá xem đường dẫn trong
VAR
có phải là tệp ống hay không. -r "$VAR"
-
Đánh giá xem người dùng hiện tại có thể đọc được đường dẫn trong
VAR
hay không. -s "$VAR"
-
Đánh giá xem đường dẫn trong
VAR
có tồn tại và nó có trống hay không. -S "$VAR"
-
Đánh giá xem đường dẫn trong
VAR
có phải là tệp ổ nối hay không. -t "$VAR"
-
Đánh giá xem đường dẫn trong
VAR
có mở trong một cửa sổ dòng lệnh hay không. -u "$VAR"
-
Đánh giá xem đường dẫn trong
VAR
có quyền SUID hay không. -w "$VAR"
-
Đánh giá xem người dùng hiện tại có thể ghi đường dẫn trong
VAR
hay không. -x "$VAR"
-
Đánh giá xem người dùng hiện tại có thể thực thi được đường dẫn trong
VAR
hay không. -O "$VAR"
-
Đánh giá xem đường dẫn trong
VAR
có thuộc quyền sở hữu của người dùng hiện tại hay không. -G "$VAR"
-
Đánh giá xem đường dẫn trong
VAR
có thuộc nhóm có hiệu lực của người dùng hiện tại hay không. -N "$VAR"
-
Đánh giá xem đường dẫn trong
VAR
có được sửa đổi kể từ lần cuối nó được truy cập hay không. "$VAR1" -nt "$VAR2"
-
Đánh giá xem đường dẫn trong
VAR1
có mới hơn đường dẫn trongVAR2
hay không (theo ngày sửa đổi của chúng). "$VAR1" -ot "$VAR2"
-
Đánh giá xem đường dẫn trong
VAR1
có cũ hơnVAR2
hay không. "$VAR1" -ef "$VAR2"
-
Đánh giá là Đúng nếu đường dẫn trong
VAR1
là liên kết cứng đếnVAR2
.
Chúng ta nên sử dụng dấu trích dẫn kép xung quanh một biến được kiểm tra vì nếu biến đó trống thì nó có thể gây ra lỗi cú pháp cho lệnh test
. Các tùy chọn kiểm tra sẽ yêu cầu một đối số toán hạng và một biến trống không được trích dẫn sẽ gây ra lỗi do thiếu đối số bắt buộc. Ngoài ra, chúng ta còn có những phiên kiểm tra các biến văn bản tùy ý được mô tả như sau:
-z "$TXT"
-
Đánh giá xem biến
TXT
có trống không (kích thước bằng 0) -n "$TXT"
hoặctest "$TXT"
-
Đánh giá xem biến
TXT
có trống không. "$TXT1" = "$TXT2"
hoặc"$TXT1" == "$TXT2"
-
Đánh giá xem
TXT1
vàTXT2
có bằng nhau không. "$TXT1" != "$TXT2"
-
Đánh giá xem
TXT1
vàTXT2
có không bằng nhau hay không. "$TXT1" < "$TXT2"
-
Đánh giá xem
TXT1
có đứng trướcTXT2
hay không, theo thứ tự bảng chữ cái. "$TXT1" > "$TXT2"
-
Đánh giá xem
TXT1
có đứng sauTXT2
hay không, theo thứ tự bảng chữ cái.
Các ngôn ngữ khác nhau có thể có các quy tắc khác nhau về thứ tự bảng chữ cái. Để có được kết quả nhất quán bất kể cài đặt cục bộ của hệ thống nơi tệp lệnh đang được thực thi có như thế nào, chúng ta nên đặt biến môi trường LANG
thành C
như trong LANG=C
trước khi thực hiện các thao tác liên quan đến thứ tự bảng chữ cái. Vì định nghĩa này cũng sẽ giữ các thông báo hệ thống ở ngôn ngữ gốc nên nó chỉ nên được sử dụng trong phạm vi của tệp lệnh.
So sánh bằng số có bộ tùy chọn kiểm tra riêng:
$NUM1 -lt $NUM2
-
Đánh giá xem
NUM1
có nhỏ hơnNUM2
hay không. $NUM1 -gt $NUM2
-
Đánh giá xem
NUM1
có lớn hơnNUM2
hay không. $NUM1 -le $NUM2
-
Đánh giá xem
NUM1
nhỏ hơn hay bằngNUM2
. $NUM1 -ge $NUM2
-
Đánh giá xem
NUM1
lớn hơn hay bằngNUM2
. $NUM1 -eq $NUM2
-
Đánh giá xem
NUM1
có bằngNUM2
hay không. $NUM1 -ne $NUM2
-
Đánh giá xem
NUM1
có không bằngNUM2
hay không.
Tất cả các phiên kiểm tra đều có thể nhận được các hiệu chỉnh sau:
! EXPR
-
Đánh giá xem biểu thức
EXPR
có sai không. EXPR1 -a EXPR2
-
Đánh giá xem cả
EXPR1
vàEXPR2
có đều đúng hay không. EXPR1 -o EXPR2
-
Đánh giá xem ít nhất một trong hai biểu thức có đúng hay không.
Một cấu trúc điều kiện khác là case
có thể được coi là một biến thể của cấu trúc if. Lệnh case
sẽ thực thi một danh sách các lệnh đã cho nếu một mục được chỉ định — ví dụ như nội dung của một biến — có thể được tìm thấy trong danh sách các mục được phân tách bằng các ống (thanh dọc |
) và được kết thúc bởi )
. Tệp lệnh mẫu sau đây cho thấy cách sử dụng cấu trúc case
để biểu thị định dạng gói phần mềm tương ứng cho một bản phân phối Linux nhất định:
#!/bin/bash DISTRO=$1 echo -n "Distribution $DISTRO uses " case "$DISTRO" in debian | ubuntu | mint) echo -n "the DEB" ;; centos | fedora | opensuse ) echo -n "the RPM" ;; *) echo -n "an unknown" ;; esac echo " package format."
Mỗi danh sách mẫu và lệnh liên quan phải được kết thúc bằng ;;
, ;&
hoặc ;;&
. Mẫu cuối cùng (dấu hoa thị) sẽ khớp nếu trước đó không có mẫu nào khác tương ứng. Lệnh esac
(ngược lại của case) sẽ kết thúc cấu trúc case
. Giả sử tệp lệnh mẫu trước đó được đặt tên là script.sh
và nó được thực thi với opensuse
làm đối số đầu tiên thì kết quả đầu ra sau sẽ được tạo:
$ ./script.sh opensuse Distribution opensuse uses the RPM package format.
Tip
|
Bash có một tùy chọn gọi là |
Mục được tìm kiếm và các mẫu sẽ trải qua quá trình mở rộng dấu ngã, mở rộng tham số, thay thế lệnh và mở rộng số học. Nếu mục tìm kiếm được chỉ định bằng dấu trích dẫn, chúng sẽ bị xóa trước khi thử khớp.
Cấu trúc Vòng lặp
Các tệp lệnh thường được sử dụng như một công cụ để tự động hóa các tác vụ lặp đi lặp lại hoặc thực hiện cùng một bộ lệnh cho đến khi tiêu chí dừng được xác minh. Bash có ba lệnh vòng lặp — for
, until
và while
— được thiết kế cho các cấu trúc vòng lặp khác biệt hơn một chút.
Cấu trúc for
sẽ duyệt qua một danh sách các mục nhất định — thường là một danh sách các từ hoặc bất kỳ đoạn văn bản nào được phân tách bằng dấu cách — và thực hiện cùng một bộ lệnh trên mỗi mục đó. Trước mỗi lần lặp, lệnh for
sẽ gán mục hiện tại cho một biến, sau đó các lệnh kèm theo có thể sử dụng mục này. Quá trình sẽ được lặp lại cho đến khi không còn mục nào nữa. Cú pháp của cấu trúc for
là:
for VARNAME in LIST do COMMANDS done
VARNAME
là tên biến vỏ tùy ý và LIST
là bất kỳ một chuỗi thuật ngữ riêng biệt nào. Các ký tự phân cách hợp lệ chia tách các mục trong danh sách sẽ được xác định bởi biến môi trường IFS
, theo mặc định là các ký tự dấu cách, tab và dòng mới. Danh sách các lệnh được thực thi sẽ được phân cách bằng lệnh do
và done
, vì vậy nên các lệnh có thể chiếm bao nhiêu dòng cũng được.
Trong ví dụ sau, lệnh for
sẽ lấy từng mục từ danh sách được cung cấp — một chuỗi số — và gán nó cho biến NUM
, mỗi lần gán một mục:
#!/bin/bash for NUM in 1 1 2 3 5 8 13 do echo -n "$NUM is " if [ $(( $NUM % 2 )) -ne 0 ] then echo "odd." else echo "even." fi done
Trong ví dụ này, một cấu trúc if
lồng được sử dụng kết hợp với một biểu thức số học để đánh giá xem số trong biến NUM
hiện tại là chẵn hay lẻ. Giả sử tệp lệnh mẫu trước đó có tên là script.sh
và nó nằm trong thư mục hiện tại, kết quả đầu ra sau sẽ được tạo:
$ ./script.sh 1 is odd. 1 is odd. 2 is even. 3 is odd. 5 is odd. 8 is even. 13 is odd.
Bash cũng hỗ trợ một định dạng thay thế cho cấu trúc for
với ký hiệu hai dấu ngoặc đơn. Ký hiệu này giống với cú pháp lệnh for
trong ngôn ngữ lập trình C và nó đặc biệt hữu ích khi làm việc với mảng:
#!/bin/bash SEQ=( 1 1 2 3 5 8 13 ) for (( IDX = 0; IDX < ${#SEQ[*]}; IDX++ )) do echo -n "${SEQ[$IDX]} is " if [ $(( ${SEQ[$IDX]} % 2 )) -ne 0 ] then echo "odd." else echo "even." fi done
Tệp lệnh mẫu này sẽ tạo ra kết quả đầu ra giống hệt như ví dụ trước. Tuy nhiên, thay vì sử dụng biến NUM
để lưu trữ từng mục một, biến IDX
sẽ được sử dụng để theo dõi chỉ số mảng hiện tại theo thứ tự tăng dần, bắt đầu từ 0 và liên tục thêm vào khi nó ở dưới số lượng mục trong mảngg SEQ
. Mục thực tế sẽ được truy xuất từ vị trí mảng của nó với ${SEQ[$IDX]}
.
Theo cách tương tự, cấu trúc until
sẽ thực thi một chuỗi lệnh cho đến khi một lệnh kiểm tra — giống như chính lệnh test
— kết thúc với trạng thái 0 (thành công). Ví dụ: cấu trúc vòng lặp tương tự từ ví dụ trước có thể được triển khai với until
như sau:
#!/bin/bash SEQ=( 1 1 2 3 5 8 13 ) IDX=0 until [ $IDX -eq ${#SEQ[*]} ] do echo -n "${SEQ[$IDX]} is " if [ $(( ${SEQ[$IDX]} % 2 )) -ne 0 ] then echo "odd." else echo "even." fi IDX=$(( $IDX + 1 )) done
Cấu trúc until
có thể yêu cầu nhiều lệnh hơn cấu trúc for
nhưng nó lại có thể phù hợp hơn với tiêu chí dừng phi số được cung cấp bởi biểu thức test
hoặc bất kỳ một lệnh nào khác. Quan trọng nhất là người dùng cần bao gồm các hành động đảm bảo tiêu chí dừng hợp lệ (chẳng hạn như mức tăng của biến đếm); nếu không, vòng lặp có thể sẽ chạy mãi mãi.
Lệnh while
cũng tương tự như until
nhưng nó sẽ tiếp tục lặp lại tập hợp lệnh nếu lệnh kiểm tra kết thúc với trạng thái 0 (thành công). Do đó, lệnh until [ $IDX -eq ${#SEQ[*]} ]
từ ví dụ trước sẽ tương đương với while [ $IDX -lt ${#SEQ[*]} ]
vì vòng lặp sẽ lặp lại trong khi chỉ số mảng sẽ nhỏ hơn tổng số mục trong mảng.
Một Ví dụ phức tạp hơn
Hãy tưởng tượng một người dùng muốn đồng bộ hóa định kỳ một tập hợp các tệp và thư mục của họ với một thiết bị lưu trữ khác được gắn tại một điểm gắn kết tùy ý trong hệ thống tệp và một hệ thống sao lưu đầy đủ tính năng thì lại quá dư thừa. Vì đây là hoạt động được thực hiện định kỳ nên tự động hóa bằng tệp lệnh vỏ là một ứng dụng rất phù hợp cho trường hợp sử dụng này.
Tác vụ rất đơn giản: đồng bộ hóa mọi tệp và thư mục có trong danh sách, từ thư mục gốc được coi là đối số tệp lệnh đầu tiên đến thư mục đích được coi là đối số tệp lệnh thứ hai. Để giúp việc thêm hoặc xóa các mục khỏi danh sách trở nên dễ dàng hơn, nó sẽ được giữ trong một tệp riêng biệt là ~/.sync.list
, một mục trên mỗi dòng:
$ cat ~/.sync.list Documents To do Work Family Album .config .ssh .bash_profile .vimrc
Tệp này có chứa hỗn hợp các tệp và thư mục, một số còn có khoảng trống trong tên của chúng. Đây là một kịch bản phù hợp cho lệnh Bash tích hợp sẵn mapfile
. Lệnh này sẽ phân tích mọi nội dung văn bản đã cho, tạo một biến mảng từ đó và đặt mỗi dòng dưới dạng một mục mảng riêng lẻ. Tệp lệnh sẽ có tên sync.sh
và có chứa tệp lệnh sau:
#!/bin/bash set -ef # List of items to sync FILE=~/.sync.list # Origin directory FROM=$1 # Destination directory TO=$2 # Check if both directories are valid if [ ! -d "$FROM" -o ! -d "$TO" ] then echo Usage: echo "$0 <SOURCEDIR> <DESTDIR>" exit 1 fi # Create array from file mapfile -t LIST < $FILE # Sync items for (( IDX = 0; IDX < ${#LIST[*]}; IDX++ )) do echo -e "$FROM/${LIST[$IDX]} \u2192 $TO/${LIST[$IDX]}"; rsync -qa --delete "$FROM/${LIST[$IDX]}" "$TO"; done
Hành động đầu tiên mà tệp lệnh sẽ thực hiện là xác định lại hai tham số vỏ bằng lệnh set
: tùy chọn -e
sẽ thoát thực thi ngay lập tức nếu một lệnh thoát với trạng thái khác 0 và tùy chọn -f
sẽ vô hiệu hóa tính năng khớp mẫu khối cho tên tệp. Cả hai tùy chọn có thể được rút ngắn thành -ef
. Đây không phải là bước bắt buộc nhưng nó sẽ giúp giảm thiểu khả năng xảy ra các hành vi không mong muốn.
Các chỉ dẫn định hướng ứng dụng thực tế của tệp lệnh có thể được chia thành ba phần:
-
Thu thập và kiểm tra tham số tệp lệnh
Biến
FILE
là đường dẫn đến tệp chứa danh sách các mục cần sao chép:~/.sync.list
. Các biếnFROM
vàTO
lần lượt là đường dẫn gốc và đích. Vì hai tham số cuối cùng này do người dùng cung cấp nên chúng sẽ trải qua một cuộc kiểm tra xác thực đơn giản được thực hiện bởi cấu trúcif
: nếu bất kỳ tham số nào trong hai tham số này không phải là thư mục hợp lệ — được đánh giá bằng phiên kiểm tra[ ! -d "$FROM" -o ! -d "$TO" ]
— tệp lệnh sẽ hiển thị một thông báo trợ giúp ngắn gọn và sau đó kết thúc với trạng thái thoát là 1. -
Tải danh sách tệp và thư mục
Sau khi tất cả các tham số được xác định, một mảng chứa danh sách các mục cần sao chép sẽ được tạo bằng lệnh
mapfile -t LIST < $FILE
. Tùy chọn-t
củamapfile
sẽ xóa ký tự dòng mới ở cuối mỗi dòng trước khi đưa nó vào biến mảng có tênLIST
. Nội dung của tệp được biểu thị bằng biếnFILE
—~/.sync.list
— được đọc thông qua chuyển hướng đầu vào. -
Thực hiện sao chép và thông báo cho người dùng
Vòng lặp
for
sử dụng ký hiệu hai dấu ngoặc đơn để duyệt qua mảng của các mục với biếnIDX
theo dõi mức tăng chỉ số. Lệnhecho
sẽ thông báo cho người dùng về từng mục được sao chép. Ký tự unicode đã thoát —\u2192
— cho ký tự mũi tên bên phải sẽ hiện diện trong thông báo đầu ra, vì thế nên ta phải sử dụng tùy chọn-e
của lệnhecho
. Lệnhrsync
sẽ chỉ sao chép có chọn lọc các phần tệp đã sửa đổi từ nguồn gốc, do đó ta nên sử dụng lệnh này cho các tác vụ như vậy. Các tùy chọn củarsync
là-q
và-a
(có thể được gói gọn thành-qa
) sẽ chặn các thông báorsync
và kích hoạt chế độ lưu trữ và tất cả các thuộc tính tệp sẽ được giữ nguyên. Tùy chọn--delete
sẽ khiếnrsync
xóa một mục ở đích không còn tồn tại ở gốc nữa, vì vậy chúng ta nên sử dụng nó một cách cẩn thận.
Giả sử tất cả các mục trong danh sách đều tồn tại trong thư mục chính của người dùng carol
(/home/carol
) và thư mục đích /media/carol/backup
trỏ đến một thiết bị lưu trữ ngoại vi được gắn kết, lệnh sync. sh /home/carol /media/carol/backup
sẽ tạo ra kết quả đầu ra sau:
$ sync.sh /home/carol /media/carol/backup /home/carol/Documents → /media/carol/backup/Documents /home/carol/"To do" → /media/carol/backup/"To do" /home/carol/Work → /media/carol/backup/Work /home/carol/"Family Album" → /media/carol/backup/"Family Album" /home/carol/.config → /media/carol/backup/.config /home/carol/.ssh → /media/carol/backup/.ssh /home/carol/.bash_profile → /media/carol/backup/.bash_profile /home/carol/.vimrc → /media/carol/backup/.vimrc
Ví dụ này cũng giả định tệp lệnh được thực thi bởi siêu người dùng hoặc bởi người dùng carol
vì hầu hết các tệp sẽ không thể đọc được bởi những người dùng khác. Nếu script.sh
không nằm trong thư mục được liệt kê trong biến môi trường PATH
thì nó phải được chỉ định bằng đường dẫn đầy đủ.
Bài tập Hướng dẫn
-
Làm cách nào để có thể sử dụng lệnh
test
để xác minh xem đường dẫn tệp được lưu trong biếnFROM
có mới hơn tệp có đường dẫn được lưu trong biếnTO
không? -
Tệp lệnh sau lẽ ra sẽ in một dãy số từ 0 đến 9, nhưng thay vào đó nó in 0 vô thời hạn. Bạn cần phải làm gì để có được kết quả như mong đợi?
#!/bin/bash COUNTER=0 while [ $COUNTER -lt 10 ] do echo $COUNTER done
-
Giả sử một người dùng đã viết một tệp lệnh yêu cầu danh sách tên người dùng được sắp xếp. Kết quả danh sách được trình bày như sau trên máy tính của họ:
carol Dave emma Frank Grace henry
Tuy nhiên, danh sách này lại được sắp xếp như sau trên máy tính của đồng nghiệp của họ:
Dave Frank Grace carol emma henry
Điều gì có thể giải thích được sự khác biệt này?
Bài tập Mở rộng
-
Làm thế nào để có thể sử dụng tất cả các đối số dòng lệnh của tệp lệnh để khởi tạo một mảng Bash?
-
Tại sao lệnh
test 1 > 2
lại được đánh giá là đúng? -
Làm cách nào để người dùng tạm thời thay đổi dấu phân cách trường mặc định thành ký tự dòng mới trong khi vẫn có thể hoàn nguyên nó về nội dung ban đầu?
Tóm tắt
Bài học này đã đi vào sâu hơn về các phiên kiểm tra có sẵn cho lệnh test
cũng như các cấu trúc vòng lặp và điều kiện khác cần thiết để viết các tệp lệnh vỏ phức tạp hơn. Một tệp lệnh đồng bộ hóa tệp đơn giản đã được đưa ra làm ví dụ về ứng dụng tệp lệnh vỏ thực tế. Bài học đã đi qua các bước sau:
-
Kiểm tra mở rộng cho cấu trúc điều kiện
if
vàcase
. -
Cấu trúc vòng lặp Vỏ:
for
,until
vàwhile
. -
Lặp qua mảng và tham số.
Các lệnh và quy trình đã được nhắc tới là:
test
-
Thực hiện so sánh giữa các mục được cung cấp cho lệnh.
if
-
Một cấu trúc logic được sử dụng trong các tệp lệnh để đánh giá điều gì đó là đúng hay sai, sau đó thực thi lệnh nhánh dựa trên kết quả.
case
-
Đánh giá nhiều giá trị dựa trên một biến duy nhất. Việc thực thi lệnh tệp lệnh sau đó sẽ được thực hiện tùy thuộc vào kết quả của lệnh
case
. for
-
Lặp lại việc thực thi một lệnh dựa trên một tiêu chí nhất định.
until
-
Lặp lại việc thực thi một lệnh cho đến khi một biểu thức được đánh giá là sai.
while
-
Lặp lại việc thực thi một lệnh trong khi một biểu thức đã cho được đánh giá là đúng.
Đáp án Bài tập Hướng dẫn
-
Làm cách nào để có thể sử dụng lệnh
test
để xác minh xem đường dẫn tệp được lưu trong biếnFROM
có mới hơn tệp có đường dẫn được lưu trong biếnTO
không?Lệnh
test "$FROM" -nt "$TO"
sẽ trả về mã trạng thái là 0 nếu tệp trong biếnFROM
mới hơn tệp trong biếnTO
. -
Tệp lệnh sau lẽ ra sẽ in một dãy số từ 0 đến 9, nhưng thay vào đó nó in 0 vô thời hạn. Bạn cần phải làm gì để có được kết quả như mong đợi?
#!/bin/bash COUNTER=0 while [ $COUNTER -lt 10 ] do echo $COUNTER done
Biến
COUNTER
phải được gia tăng. Điều này có thể được thực hiện bằng biểu thức số họcCOUNTER=$(( $COUNTER + 1 ))
để đạt được tiêu chí dừng và kết thúc vòng lặp. -
Giả sử một người dùng đã viết một tệp lệnh yêu cầu danh sách tên người dùng được sắp xếp. Kết quả danh sách được trình bày như sau trên máy tính của họ:
carol Dave emma Frank Grace henry
Tuy nhiên, danh sách này lại được sắp xếp như sau trên máy tính của đồng nghiệp của họ:
Dave Frank Grace carol emma henry
Điều gì có thể giải thích được sự khác biệt này?
Việc sắp xếp dựa trên ngôn ngữ của hệ thống hiện tại. Để tránh sự mâu thuẫn, các tác vụ sắp xếp phải được thực hiện với biến môi trường
LANG
được đặt thànhC
.
Đáp án Bài tập Mở rộng
-
Làm thế nào để có thể sử dụng tất cả các đối số dòng lệnh của tệp lệnh để khởi tạo một mảng Bash?
Các lệnh
PARAMS=( $* )
hoặcPARAMS=( "$@" )
sẽ tạo ra một mảng có tênPARAMS
với tất cả các đối số. -
Tại sao lệnh
test 1 > 2
lại được đánh giá là đúng?Toán tử
>
được thiết kế để sử dụng với các phiên kiểm tra chuỗi chứ không phải các phiên kiểm tra số. -
Làm cách nào để người dùng tạm thời thay đổi dấu phân cách trường mặc định thành ký tự dòng mới trong khi vẫn có thể hoàn nguyên nó về nội dung ban đầu?
Một bản sao của biến
IFS
có thể được lưu trữ trong một biến khác:OLDIFS=$IFS
. Sau đó, dấu tách dòng mới sẽ được xác định bằngIFS=$'\n'
và biến IFS có thể được hoàn nguyên trở lại bằngIFS=$OLDIFS
.