105.2 Bài 1
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: |
1 trên 2 |
Giới thiệu
Môi trường vỏ Linux cho phép người dùng sử dụng các tệp — được gọi là tệp lệnh — có chứa các lệnh từ bất kỳ một chương trình có sẵn nào trong hệ thống kết hợp với các lệnh vỏ tích hợp sẵn để tự động hóa các tác vụ tùy chỉnh của người dùng và/hoặc hệ thống. Thực chất có rất nhiều tác vụ bảo trì hệ điều hành được thực hiện bằng các tệp lệnh bao gồm các chuỗi lệnh, cấu trúc quyết định và vòng lặp điều kiện. Mặc dù các tệp lệnh hầu hết đều được dành cho các tác vụ liên quan đến chính hệ điều hành nhưng chúng cũng rất hữu ích cho các tác vụ hướng tới người dùng như đổi tên tệp hàng loạt, thu thập và phân tích dữ liệu hoặc bất kỳ hoạt động dòng lệnh lặp đi lặp lại nào khác.
Các tệp lệnh chỉ là các tệp văn bản hoạt động giống như các chương trình không hơn không kém. Một chương trình thực tế - trình thông dịch - sẽ đọc và thực thi các hướng dẫn được liệt kê trong tệp lệnh. Trình thông dịch cũng có thể bắt đầu một phiên tương tác mà trong đó, các lệnh — bao gồm các tệp lệnh — sẽ được đọc và thực thi khi chúng được nhập (như trường hợp của các phiên vỏ Linux). Các tệp lệnh có thể nhóm các hướng dẫn và lệnh đó khi chúng quá phức tạp để có thể triển khai dưới dạng bí danh hoặc hàm vỏ tùy chỉnh. Hơn nữa, các tệp lệnh có thể được duy trì giống như các chương trình thông thường và vì bản chất chỉ là các tệp văn bản, chúng có thể được tạo và sửa đổi bằng bất kỳ trình soạn thảo văn bản đơn giản nào.
Cấu trúc và việc thực thi Tệp lệnh
Về cơ bản, tệp lệnh là một chuỗi lệnh được sắp xếp phải được thực thi bởi trình thông dịch lệnh tương ứng. Cách mỗi trình thông dịch đọc tệp lệnh sẽ khác nhau và có nhiều cách khác nhau để thực hiện tác vụ này trong một phiên vỏ Bash. Trình thông dịch mặc định cho tệp lệnh sẽ là trình thông dịch được chỉ định trong dòng đầu tiên của tệp lệnh ngay sau các ký tự \# !
(được gọi là shebang). Trong một tệp lệnh có hướng dẫn về vỏ Bash, dòng đầu tiên phải là !/bin/bash
. Bằng cách chỉ ra dòng này, trình thông dịch cho tất cả các hướng dẫn trong tệp sẽ là /bin/bash
. Ngoại trừ dòng đầu tiên, tất cả các dòng khác bắt đầu bằng ký tự sẽ bị bỏ qua. Vì vậy, chúng có thể được sử dụng để đặt lời nhắc và chú thích. Các dòng trống cũng sẽ bị bỏ qua. Do đó, một tệp lệnh vỏ ngắn gọn có thể được viết như sau:
#!/bin/bash # A very simple script echo "Cheers from the script file! Current time is: " date +%H:%M
Tệp lệnh này chỉ có hai hướng dẫn cho trình thông dịch /bin/bash
: lệnh tích hợp sẵn echo
và lệnh date
. Cách cơ bản nhất để chạy tệp lệnh là thực thi trình thông dịch với đường dẫn tệp lệnh làm đối số. Vì vậy, giả sử ví dụ trước được lưu trong tệp lệnh có tên script.sh
trong thư mục hiện tại, nó sẽ được Bash đọc và diễn giải bằng lệnh sau:
$ bash script.sh Cheers from the script file! Current time is: 10:57
Lệnh echo
sẽ tự động thêm một dòng mới sau khi hiển thị nội dung, nhưng tùy chọn -n
sẽ ngăn chặn hành vi này. Do đó, việc sử dụng echo -n
trong tệp lệnh sẽ làm cho đầu ra của cả hai lệnh xuất hiện trên cùng một dòng:
$ bash script.sh Cheers from the script file! Current time is: 10:57
Mặc dù không bắt buộc nhưng hậu tố .sh
sẽ giúp xác định các tệp lệnh vỏ khi liệt kê và tìm kiếm tệp.
Tip
|
Bash sẽ gọi bất kỳ lệnh nào được chỉ định sau |
Nếu tệp lệnh được dự định để những người dùng khác trong hệ thống thực thi, quan trọng nhất là ta phải kiểm tra xem quyền đọc thích hợp có được đặt hay không. Lệnh chmod o+r script.sh
sẽ cấp quyền đọc cho tất cả người dùng trong hệ thống và cho phép họ thực thi script.sh
bằng cách đặt đường dẫn đến tệp lệnh làm đối số của lệnh bash
. Ngoài ra, tệp lệnh có thể được đặt quyền thực thi bit để tệp có thể được thực thi như một lệnh thông thường. Bit thực thi có thể được kích hoạt trên tệp lệnh bằng lệnh chmod
:
$ chmod +x script.sh
Khi bit thực thi được bật, tệp lệnh có tên script.sh
trong thư mục hiện tại có thể được thực thi trực tiếp bằng lệnh ./script.sh
. Các tệp lệnh được đặt trong thư mục được liệt kê trong biến môi trường PATH
cũng sẽ có thể được truy cập mà không cần đường dẫn đầy đủ của chúng.
Warning
|
Một tệp lệnh thực hiện các hành động bị hạn chế có thể được kích hoạt quyền SUID để người dùng thông thường cũng có thể chạy nó với quyền gốc. Trong trường hợp này, điều rất quan trọng là phải đảm bảo rằng không có người dùng nào ngoài siêu người dùng có quyền ghi vào tệp. Nếu không, người dùng thông thường có thể sửa đổi tệp để thực hiện các hoạt động tùy ý và sẽ có khả năng gây hại. |
Việc sắp xếp và thụt lề các lệnh trong tệp lệnh sẽ không quá cứng nhắc. Mỗi dòng trong một tệp lệnh vỏ sẽ được thực thi như một lệnh vỏ thông thường theo cùng trình tự xuất hiện của các dòng trong tệp lệnh. Các quy tắc áp dụng cho dấu nhắc lệnh vỏ tương tự cũng sẽ áp dụng cho từng dòng tập lệnh riêng lẻ. Ta có thể đặt hai hoặc nhiều lệnh trên cùng một dòng và phân tách bằng dấu chấm phẩy:
echo "Cheers from the script file! Current time is:" ; date +%H:%M
Mặc dù đôi khi định dạng này có thể sẽ thuận tiện hơn nhưng việc sử dụng nó là tùy chọn vì các lệnh tuần tự có thể được đặt mỗi dòng một lệnh và chúng sẽ được thực thi theo như cách chúng được phân tách. Nói cách khác, dấu chấm phẩy có thể được thay thế bằng một ký tự dòng mới trong tệp lệnh Bash.
Khi một tệp lệnh được thực thi, các lệnh ở trong nó sẽ không được thực thi trực tiếp trong phiên hiện tại mà thay vào đó là bởi một tiến trình Bash mới được gọi là vỏ con. Nó sẽ ngăn tệp lệnh ghi đè các biến môi trường của phiên hiện tại và để lại các sửa đổi không được giám sát trong phiên hiện tại. Nếu mục tiêu của người dùng là chạy nội dung của tệp lệnh trong phiên vỏ hiện tại thì nó phải được thực thi bằng source script.sh
hoặc . script.sh
(hãy lưu ý rằng có một khoảng cách giữa dấu chấm và tên tệp lệnh).
Giống như khi thực thi bất kỳ một lệnh nào khác, dấu nhắc lệnh vỏ sẽ chỉ khả dụng trở lại khi tệp lệnh kết thúc việc thực thi và mã trạng thái thoát của nó sẽ có sẵn trong biến $?
. Để thay đổi hành vi này để vỏ hiện tại cũng kết thúc khi tệp lệnh kết thúc, tệp lệnh — hoặc bất kỳ một lệnh nào khác — có thể được đặt trước lệnh exec
. Lệnh này cũng sẽ thay thế mã trạng thái thoát của phiên vỏ hiện tại bằng mã riêng của nó.
Biến
Biến trong tệp lệnh vỏ hoạt động giống như trong các phiên tương tác với điều kiện là trình thông dịch phải giống nhau. Ví dụ: định dạng SOLUTION=42
(không có khoảng trắng xung quanh dấu bằng) sẽ gán giá trị 42
cho biến có tên là SOLUTION
. Theo quy ước, chữ in hoa sẽ được sử dụng cho tên biến (nhưng không bắt buộc). Tuy nhiên, tên biến không thể bắt đầu bằng các ký tự không nằm trong bảng chữ cái.
Ngoài các biến thông thường do người dùng tạo, tệp lệnh Bash còn có một tập hợp các biến đặc biệt được gọi là tham số. Không giống như các biến thông thường, tên tham số sẽ bắt đầu bằng ký tự không phải chữ cái để chỉ định chức năng của nó. Các đối số được truyền cho tệp lệnh và các thông tin hữu ích khác được lưu trữ trong các tham số như $0
, $*
, $?
, v.v. mà trong đó, ký tự theo sau ký hiệu đô la sẽ biểu thị thông tin cần tìm nạp:
$*
-
Tất cả các đối số được truyền cho tệp lệnh.
$@
-
Tất cả các đối số được truyền cho tệp lệnh. Nếu được sử dụng với dấu trích dẫn kép (như trong
"$@"
), mọi đối số sẽ được đặt trong dấu trích dẫn kép. $#
-
Số lượng đối số.
$0
-
Tên của tệp lệnh.
$!
-
PID của chương trình được thực hiện cuối cùng.
$$
-
PID của vỏ hiện tại.
$?
-
Mã trạng thái thoát bằng số của lệnh được hoàn thành cuối cùng. Đối với các tiến trình tiêu chuẩn POSIX, giá trị số
0
có nghĩa là lệnh cuối cùng đã được thực thi thành công; điều này cũng áp dụng cho các tệp lệnh vỏ.
Một tham số vị trí là một tham số được biểu thị bằng một hoặc nhiều chữ số khác 0
. Ví dụ: biến $1
tương ứng với đối số đầu tiên được cung cấp cho tệp lệnh (tham số vị trí một), $2
tương ứng với đối số thứ hai, v.v. Nếu vị trí của một tham số lớn hơn chín thì tham số đó phải được tham chiếu bằng dấu ngoặc nhọn như trong ${10}
, ${11}
, v.v.
Mặt khác, các biến thông thường được nhắm tới mục đích lưu trữ các giá trị được chèn thủ công hoặc đầu ra được tạo bởi các lệnh khác. Ví dụ: lệnh read
có thể được sử dụng bên trong tệp lệnh để yêu cầu người dùng nhập thông tin trong quá trình thực thi tệp lệnh:
echo "Do you want to continue (y/n)?" read ANSWER
Giá trị trả về sẽ được lưu trữ trong biến ANSWER
. Nếu tên biến không được cung cấp, tên biến REPLY
sẽ được sử dụng theo mặc định. Ta cũng có thể sử dụng lệnh read
để đọc nhiều biến cùng một lúc:
echo "Type your first name and last name:" read NAME SURNAME
Trong trường hợp này, mỗi số hạng được phân tách bằng dấu cách sẽ được gán tương ứng cho các biến NAME
và SURNAME
. Nếu số của các số hạng đã cho lớn hơn số biến thì chúng sẽ được lưu vào biến cuối cùng. Bản thân read
có thể hiển thị thông báo cho người dùng với tùy chọn -p
để khiến lệnh echo
trở nên không cần thiết trong trường hợp này:
read -p "Type your first name and last name:" NAME SURNAME
Các tệp lệnh thực hiện tác vụ hệ thống thường sẽ yêu cầu thông tin do các chương trình khác cung cấp. Ký hiệu trích dẫn đơn ngược (`) có thể được sử dụng để lưu trữ kết quả đầu ra của lệnh trong một biến:
$ OS=`uname -o`
Trong ví dụ, đầu ra của lệnh uname -o
sẽ được lưu trong biến OS
. Một kết quả giống hệt sẽ được tạo ra với $()
:
$ OS=$(uname -o)
Độ dài của một biến (tức là số lượng ký tự mà nó chứa) sẽ được trả về bằng cách thêm một hàm băm #
vào trước tên của biến. Tuy nhiên, tính năng này yêu cầu sử dụng cú pháp dấu ngoặc nhọn để biểu thị biến:
$ OS=$(uname -o) $ echo $OS GNU/Linux $ echo ${#OS} 9
Bash cũng có các biến mảng một chiều. Do đó, một tập hợp các phần tử liên quan có thể được lưu trữ bằng một tên biến duy nhất. Mỗi phần tử trong mảng đều có một chỉ mục bằng số. Chỉ số này phải được sử dụng để ghi và đọc các giá trị trong phần tử tương ứng. Khác với các biến thông thường, mảng phải được khai báo bằng lệnh declare
tích hợp sẵn của Bash. Ví dụ: để khai báo một biến có tên SIZES
dưới dạng một mảng:
$ declare -a SIZES
Mảng cũng có thể được khai báo ngầm khi điền từ danh sách các mục được xác định trước bằng cách sử dụng ký hiệu dấu ngoặc đơn:
$ SIZES=( 1048576 1073741824 )
Trong ví dụ này, hai giá trị số nguyên lớn đã được lưu trữ trong mảng SIZES
. Các phần tử mảng phải được tham chiếu bằng dấu ngoặc nhọn và ngoặc vuông. Nếu không, Bash sẽ không thay đổi hoặc hiển thị phần tử một cách chính xác. Vì các chỉ mục mảng bắt đầu từ 0 nên nội dung của phần tử đầu tiên sẽ nằm trong ${SIZES[0]}
, phần tử thứ hai sẽ nằm trong ${SIZES[1]}
, v.v.
$ echo ${SIZES[0]} 1048576 $ echo ${SIZES[1]} 1073741824
Không giống như việc đọc, việc thay đổi nội dung của phần tử mảng có thể được thực hiện mà không cần dấu ngoặc nhọn (ví dụ: SIZES[0]=1048576
). Giống như các biến thông thường, độ dài của một phần tử trong một mảng sẽ được trả về bằng ký tự băm (ví dụ: ${#SIZES[0]}
cho độ dài của phần tử đầu tiên trong mảng SIZES
). Tổng số phần tử trong một mảng sẽ được trả về nếu @
hoặc *
được sử dụng làm chỉ mục:
$ echo ${#SIZES[@]} 2 $ echo ${#SIZES[*]} 2
Mảng cũng có thể được khai báo bằng cách sử dụng đầu ra của lệnh làm phần tử ban đầu thông qua thay thế lệnh. Ví dụ sau đây sẽ cho thấy cách tạo một mảng Bash có các phần tử là hệ thống tệp được hỗ trợ của hệ thống hiện tại:
$ FS=( $(cut -f 2 < /proc/filesystems) )
Lệnh cut -f 2 < /proc/filesystems
sẽ hiển thị tất cả các hệ thống tệp hiện được hỗ trợ bởi hạt nhân đang chạy (như được liệt kê trong cột thứ hai của tệp /proc/filesystems
). Vì vậy, mảng FS
hiện sẽ chứa một phần tử cho mỗi một hệ thống tệp được hỗ trợ. Bất kỳ nội dung văn bản nào cũng có thể được sử dụng để khởi tạo một mảng vì theo mặc định, mọi thuật ngữ được phân cách bằng các ký tự dấu cách, tab hoặc dấu xuống dòng sẽ trở thành một phần tử mảng.
Tip
|
Bash coi mỗi ký tự của |
Biểu thức Số học
Bash có cung cấp một phương pháp thực tế để thực hiện các phép tính số học số nguyên bằng lệnh tích hợp sẵn expr
. Ví dụ: hai biến số $VAL1
và $VAL2
có thể được cộng lại bằng lệnh sau:
$ SUM=`expr $VAL1 + $VAL2`
Giá trị kết quả của ví dụ sẽ có sẵn trong biến $SUM
. Lệnh expr
có thể được thay thế bằng $(())
. Vì vậy, ví dụ trước có thể được viết lại thành SUM=$(( $VAL1 + $VAL2 ))
. Biểu thức lũy thừa cũng được cho phép với toán tử dấu hoa thị kép. Vì vậy, phần khai báo mảng trước đó SIZES=( 1048576 1073741824)
có thể được viết lại thành SIZES=( $((1024**2)) $((1024 **3)) )
.
Thay thế lệnh cũng có thể được sử dụng trong các biểu thức số học. Ví dụ: tệp /proc/meminfo
có thông tin chi tiết về bộ nhớ hệ thống bao gồm số byte trống trong RAM:
$ FREE=$(( 1000 * `sed -nre '2s/[^[:digit:]]//gp' < /proc/meminfo` ))
Ví dụ này cho thấy lệnh sed
có thể được sử dụng như thế nào để phân tích nội dung của /proc/meminfo
bên trong biểu thức số học. Dòng thứ hai của tệp /proc/meminfo
có chứa lượng bộ nhớ trống tính bằng hàng nghìn byte. Do đó, biểu thức số học sẽ nhân nó với 1000 để có được số byte trống trong RAM.
Thực thi có điều kiện
Một số tệp lệnh thường không nhằm mục đích thực thi tất cả các lệnh trong tệp lệnh mà chỉ những lệnh phù hợp với tiêu chí đã được xác định trước. Ví dụ: một tệp lệnh bảo trì chỉ có thể gửi thông báo cảnh báo đến email của quản trị viên nếu việc thực thi lệnh không thành công. Bash có cung cấp các phương pháp cụ thể để đánh giá sự thành công của việc thực thi lệnh và các cấu trúc điều kiện chung tương tự như các phương pháp được tìm thấy trong các ngôn ngữ lập trình phổ biến.
Bằng cách tách các lệnh với &&
, lệnh bên phải sẽ chỉ được thực thi nếu lệnh bên trái không gặp lỗi, nghĩa là nếu trạng thái thoát của nó bằng 0
:
COMMAND A && COMMAND B && COMMAND C
Hành vi ngược lại sẽ xảy ra nếu các lệnh được phân tách bằng ||
. Trong trường hợp này, lệnh sau sẽ chỉ được thực thi nếu lệnh trước đó gặp lỗi, nghĩa là nếu mã trạng thái trả về của nó khác 0.
Một trong những tính năng quan trọng nhất của tất cả các ngôn ngữ lập trình là khả năng thực thi các lệnh tùy thuộc vào các điều kiện đã xác định trước đó. Cách đơn giản nhất để thực thi các lệnh có điều kiện là sử dụng lệnh if
tích hợp sẵn của Bash. Lệnh này sẽ chỉ thực thi một hoặc nhiều lệnh nếu lệnh được đưa ra làm đối số trả về mã trạng thái 0 (thành công). Một lệnh khác là test
có thể được sử dụng để đánh giá nhiều tiêu chí đặc biệt khác nhau, vì thế mà nó chủ yếu được sử dụng cùng với if
. Trong ví dụ sau, thông báo Confirmed: /bin/bash is executable.
sẽ được hiển thị nếu tệp /bin/bash
tồn tại và nó có thể thực thi được:
if test -x /bin/bash ; then echo "Confirmed: /bin/bash is executable." fi
Tùy chọn -x
sẽ khiến lệnh test
chỉ trả về mã trạng thái 0 nếu đường dẫn đã cho là một tệp thực thi. Vì dấu ngoặc vuông có thể được sử dụng để thay thế cho test
, ví dụ sau đây sẽ cho thấy một cách khác để đạt được kết quả tương tự:
if [ -x /bin/bash ] ; then echo "Confirmed: /bin/bash is executable." fi
Lệnh else
là tùy chọn đối với cấu trúc if
và nếu được sử dụng, nó có thể xác định một lệnh hoặc chuỗi lệnh để thực thi nếu biểu thức điều kiện không đúng:
if [ -x /bin/bash ] ; then echo "Confirmed: /bin/bash is executable." else echo "No, /bin/bash is not executable." fi
Cấu trúc if
phải luôn được kết thúc bằng fi
để trình thông dịch Bash biết nơi các lệnh điều kiện kết thúc.
Đầu ra của Tệp lệnh
Ngay cả khi mục đích của tệp lệnh chỉ liên quan đến các thao tác hướng đến tệp, quan trọng nhất là ta phải hiển thị các thông báo liên quan đến tiến trình ở đầu ra tiêu chuẩn để người dùng luôn được thông báo về mọi vấn đề và cuối cùng có thể sử dụng các thông báo đó để tạo nhật ký vận hành.
Lệnh tích hợp sẵn của Bash là echo
thường được sử dụng để hiển thị các chuỗi văn bản đơn giản nhưng nó cũng cung cấp một số tính năng mở rộng. Với tùy chọn -e
, lệnh echo
có thể hiển thị các ký tự đặc biệt bằng cách sử dụng các chuỗi thoát (một chuỗi dấu gạch chéo ngược chỉ định một ký tự đặc biệt). Ví dụ:
#!/bin/bash # Get the operating system's generic name OS=$(uname -o) # Get the amount of free memory in bytes FREE=$(( 1000 * `sed -nre '2s/[^[:digit:]]//gp' < /proc/meminfo` )) echo -e "Operating system:\t$OS" echo -e "Unallocated RAM:\t$(( $FREE / 1024**2 )) MB"
Mặc dù việc sử dụng dấu trích dẫn là tùy chọn khi sử dụng lệnh echo
mà không có tùy chọn, ta sẽ phải thêm chúng khi sử dụng tùy chọn -e
. Nếu không, các ký tự đặc biệt có thể sẽ không hiển thị chính xác. Trong tệp lệnh trước, cả hai lệnh echo
đều sử dụng ký tự lập bảng \t
để căn chỉnh văn bản và dẫn đến kết quả đầu ra sau:
Operating system: GNU/Linux Unallocated RAM: 1491 MB
Ký tự dòng mới \n
có thể được sử dụng để phân tách các dòng đầu ra, từ đó ta có thể có được kết quả đầu ra giống hệt nhau bằng cách kết hợp hai lệnh echo
thành một:
echo -e "Operating system:\t$OS\nUnallocated RAM:\t$(( $FREE / 1024**2 )) MB"
Mặc dù có thể hiển thị hầu hết các thông báo văn bản, lệnh echo
có thể sẽ không phù hợp lắm cho việc hiển thị các mẫu văn bản cụ thể hơn. Lệnh tích hợp sẵn printf
cung cấp nhiều quyền kiểm soát hơn về cách hiển thị các biến. Lệnh printf
sử dụng đối số đầu tiên làm định dạng đầu ra mà trong đó, các ký tự giữ chỗ sẽ được thay thế bằng các đối số sau theo thứ tự chúng xuất hiện trong dòng lệnh. Ví dụ: thông báo của ví dụ trước có thể được tạo bằng lệnh printf
sau:
printf "Operating system:\t%s\nUnallocated RAM:\t%d MB\n" $OS $(( $FREE / 1024**2 ))
Ký tự giữ chỗ %s
được dành cho nội dung văn bản (nó sẽ được thay thế bằng biến $OS
) và ký tự giữ chỗ %d
được dành cho số nguyên (nó sẽ được thay thế bằng số megabyte trống trong RAM ). Lệnh printf
sẽ không thêm ký tự dòng mới vào cuối văn bản, vì thế mà ký tự dòng mới \n
nên được đặt ở cuối mẫu nếu cần. Toàn bộ mẫu phải được hiểu là một đối số duy nhất. Vì vậy, nó phải được đặt trong dấu trích dẫn kép.
Tip
|
Định dạng của ký tự giữ chỗ thay thế được thực hiện bởi |
Với printf
, các biến sẽ được đặt bên ngoài mẫu văn bản. Điều này giúp chúng ta lưu trữ mẫu văn bản trong một biến riêng biệt:
MSG='Operating system:\t%s\nUnallocated RAM:\t%d MB\n' printf "$MSG" $OS $(( $FREE / 1024**2 ))
Phương pháp này đặc biệt hữu ích trong việc hiển thị các định dạng đầu ra riêng biệt, tùy thuộc vào yêu cầu của người dùng. Ví dụ: sẽ dễ dàng hơn khi ta viết tệp lệnh sử dụng mẫu văn bản riêng biệt nếu người dùng yêu cầu danh sách CSV (Giá trị được phân tách bằng dấu phẩy) thay vì thông báo đầu ra mặc định.
Bài tập Hướng dẫn
-
Tùy chọn
-s
cho lệnhread
rất hữu ích cho việc nhập mật khẩu vì nó sẽ không hiển thị nội dung được nhập trên màn hình. Làm thế nào để có thể sử dụng lệnhread
để lưu trữ dữ liệu đầu vào của người dùng trong biếnPASSWORD
trong khi ẩn nội dung đã nhập? -
Mục đích duy nhất của lệnh
whoami
là để hiển thị tên người dùng đã gọi nó. Vì vậy, nó chủ yếu được sử dụng bên trong các tệp lệnh để xác định người dùng đang chạy tệp lệnh. Bên trong tệp lệnh Bash, làm thế nào để đầu ra của lệnhwhoami
có thể được lưu trữ trong biến có tênWHO
? -
Toán tử Bash nào nên nằm giữa các lệnh
apt-get dist-upgrade
vàsystemctl restart
nếu siêu người dùng (root) chỉ muốn thực thisystemctl restart
trong trường hợpapt-get dist-upgrade
hoàn tất thành công?
Bài tập Mở rộng
-
Sau khi thử chạy tệp lệnh Bash mới được tạo, người dùng nhận được thông báo lỗi sau:
bash: ./script.sh: Permission denied
Lưu ý rằng tệp
./script.sh
được tạo bởi cùng một người dùng, nguyên nhân có thể gây ra lỗi này là gì? -
Giả sử một tệp lệnh có tên
do.sh
có thể thực thi được và liên kết tượng trưng có tênundo.sh
trỏ đến nó. Từ trong tệp lệnh, làm cách nào để có thể xác định tên tệp đang gọi làdo.sh
hayundo.sh
? -
Trong hệ thống có một dịch vụ email được cấu hình đúng cách, lệnh
mail -s "Maintenance Error" root <<<"Scheduled task error"
sẽ gửi thông báo email đến siêu người dùng. Lệnh như vậy có thể được sử dụng trong các tác vụ không được giám sát (như các công việc định kỳ) để thông báo cho quản trị viên hệ thống về một sự cố không mong muốn. Hãy viết cấu trúc if sẽ thực thi lệnhmail
đã nói ở trên nếu trạng thái thoát của lệnh trước đó — bất kể đó là gì — là không thành công.
Tóm tắt
Bài học này bao gồm các khái niệm cơ bản để hiểu và viết các tệp lệnh vỏ Bash. Các tệp lệnh Vỏ là một phần cốt lõi của bất kỳ bản phân phối Linux nào vì chúng cung cấp một cách rất linh hoạt để tự động hóa các tác vụ hệ thống và người dùng được thực hiện trong môi trường vỏ. Bài học đã đi qua các bước sau:
-
Cấu trúc tệp lệnh Vỏ và quyền truy cập tệp lệnh chính xác
-
Thông số tệp lệnh
-
Sử dụng các biến để đọc đầu vào của người dùng và lưu trữ đầu ra của lệnh
-
Mảng Bash
-
Kiểm tra đơn giản và thực thi có điều kiện
-
Định dạng đầu ra
Các lệnh và quy trình đã được nhắc đến là:
-
Ký hiệu tích hợp sẵn của Bash để thay thế lệnh, mở rộng mảng và biểu thức số học
-
Thực thi lệnh có điều kiện với toán tử
||
và&&
-
echo
-
chmod
-
exec
-
read
-
declare
-
test
-
if
-
printf
Đáp án Bài tập Hướng dẫn
-
Tùy chọn
-s
cho lệnhread
rất hữu ích cho việc nhập mật khẩu vì nó sẽ không hiển thị nội dung được nhập trên màn hình. Làm thế nào để có thể sử dụng lệnhread
để lưu trữ dữ liệu đầu vào của người dùng trong biếnPASSWORD
trong khi ẩn nội dung đã nhập?read -s PASSWORD
-
Mục đích duy nhất của lệnh
whoami
là để hiển thị tên người dùng đã gọi nó. Vì vậy, nó chủ yếu được sử dụng bên trong các tệp lệnh để xác định người dùng đang chạy tệp lệnh. Bên trong tệp lệnh Bash, làm thế nào để đầu ra của lệnhwhoami
có thể được lưu trữ trong biến có tênWHO
?WHO=`whoami`
orWHO=$(whoami)
-
Toán tử Bash nào nên nằm giữa các lệnh
apt-get dist-upgrade
vàsystemctl restart
nếu siêu người dùng (root) chỉ muốn thực thisystemctl restart
trong trường hợpapt-get dist-upgrade
hoàn tất thành công?Toán tử
&&
, như trongapt-get dist-upgrade && systemctl restart
.
Đáp án Bài tập Mở rộng
-
Sau khi thử chạy tệp lệnh Bash mới được tạo, người dùng nhận được thông báo lỗi sau:
bash: ./script.sh: Permission denied
Lưu ý rằng tệp
./script.sh
được tạo bởi cùng một người dùng, nguyên nhân có thể gây ra lỗi này là gì?Tệp
./script.sh
chưa được gán quyền thực thi. -
Giả sử một tệp lệnh có tên
do.sh
có thể thực thi được và liên kết tượng trưng có tênundo.sh
trỏ đến nó. Từ trong tệp lệnh, làm cách nào để có thể xác định tên tệp đang gọi làdo.sh
hayundo.sh
?Biến đặc biệt
$0
chứa tên tệp được sử dụng để gọi tệp lệnh. -
Trong hệ thống có một dịch vụ email được cấu hình đúng cách, lệnh
mail -s "Maintenance Error" root <<<"Scheduled task error"
sẽ gửi thông báo email đến siêu người dùng. Lệnh như vậy có thể được sử dụng trong các tác vụ không được giám sát (như các công việc định kỳ) để thông báo cho quản trị viên hệ thống về một sự cố không mong muốn. Hãy viết cấu trúc if sẽ thực thi lệnhmail
đã nói ở trên nếu trạng thái thoát của lệnh trước đó — bất kể đó là gì — là không thành công.if [ "$?" -ne 0 ]; then mail -s "Maintenance Error" root <<<"Scheduled task error"; fi