Ngày nay công nghệ thông tin đã có những bước tiến vượt bậc. Lập trình máy tính điện tử, viết nên các chương trình ứng dụng đang ngày một gần gũi với con người. Điều đó tạo nên sự phát triển mạnh mẽ của các ngôn ngữ lập trình. Có những ngôn ngữ không phụ thuộc hệ điều hành, nhưng bên cạnh đó cũng có những ngôn ngữ gắn liền với hệ điều hành, phát triển trên nền hệ điều hành và tác động trực tiếp đến các quá trình quản lý cũng như xử lý của hệ điều hành. Shell là ngôn ngữ chính của hệ điều hành Linux – hệ điều hành mã nguồn mở, hay trước đây còn được biết đến là hệ điều hành chế độ dòng lệnh. Có thể thấy shell đóng vai trò quan trọng và có tầm ảnh hưởng to lớn đến hệ điều hành này. Tất cả các thao tác quản trị cũng như xử lý của hệ điều hành đều thông qua shell. Với sự phát triển mạnh mẽ của Linux, việc tìm hiểu shell là hết sức cần thiết....
Trang 1Lời nói đầu
Ngày nay công nghệ thông tin đã có những bước tiến vượt bậc Lập trình máy tính điện tử, viết nên các chương trình ứng dụng đang ngày một gần gũi với con người Điều
đó tạo nên sự phát triển mạnh mẽ của các ngôn ngữ lập trình Có những ngôn ngữ không phụ thuộc hệ điều hành, nhưng bên cạnh đó cũng có những ngôn ngữ gắn liền với hệ điều hành, phát triển trên nền hệ điều hành và tác động trực tiếp đến các quá trình quản
lý cũng như xử lý của hệ điều hành
Shell là ngôn ngữ chính của hệ điều hành Linux – hệ điều hành mã nguồn mở, hay trước đây còn được biết đến là hệ điều hành chế độ dòng lệnh Có thể thấy shell đóng vai trò quan trọng và có tầm ảnh hưởng to lớn đến hệ điều hành này Tất cả các thao tác quản trị cũng như xử lý của hệ điều hành đều thông qua shell Với sự phát triển mạnh
mẽ của Linux, việc tìm hiểu shell là hết sức cần thiết Với nhu cầu đó, nhóm chúng em
đã chọn đề tài tiểu luận “Tìm hiểu ngôn ngữ Shell Script” Tuy đã rất cố gắng nhưng do thời gian có hạn, báo cáo của chúng em không tránh khỏi những thiếu sót
Chúng em xin chân thành cảm ơn thầy đã tạo điều kiện và giúp đỡ chúng em hoàn thành tiểu luận này
Trang 2Mục lục
Chương 1-Sơ lược về Shell 3
1.1 Kernel là gì? 3
1.2 Shell là gì? 4
1.3 Phân loại Shell 5
1.3.1 Bourne Shell 5
1.3.2 C Shell 5
1.3.3 Korn Shell 6
1.3.4 Bash Shell 6
Chương 2-Cú pháp ngôn ngữ shell script 8
2.1 Chương trình Hello World 8
2.2 Sử dụng biến 9
2.3 Phân biệt dấu nháy kép (“), dấu nháy đơn (') và dấu thực thi (`) 11
2.3.1 Dấu thực thi (`) 11
2.3.2 Dấu nháy kép (“) và nháy đơn (') 11
2.4 Cấu trúc trong ngôn ngữ shell script 12
2.4.1 Cấu trúc điều kiện 12
2.4.1.1 Cấu trúc if 12
2.4.1.2 Cấu trúc case 13
2.4.2 Cấu trúc điều khiển 15
2.4.2.1 Vòng lặp for 15
2.4.2.2 Vòng lặp while và until 17
Chương 3-Chuyển hướng xuất nhập 18
3.1 Làm việc với dòng vào chuẩn và dòng ra chuẩn 18
3.2 Chuyển hướng xuất nhập 19
3.3 Chuyển hướng stderr (dòng lỗi chuẩn) 20
3.4 Chuyển hướng đồng thời stdout và stderr 21
3.5 Kỹ thuật pipeline 22
Chương 4-Kỹ thuật debug trong shell script 28
4.1 Giải mã thông báo lỗi 28
4.1.1 Tìm lỗi cú pháp 28
4.1.2 Kỹ thuật chia để trị 32
4.2 Chế độ Debug 33
4.2.1 Disabling the Shell 33
4.2.2 Dò lỗi thực thi 34
4.3 Tránh lỗi bằng thói quen lập trình 35
4.3.1 Script sáng sủa 35
4.3.2 Chú thích 36
Trang 3Chương 1- Sơ lược về Shell
Để đi vào tìm hiểu về shell cũng như ngôn ngữ shell script, chúng ta hãy cùng xem xét kernel là gì?
1.1 Kernel là gì?
Ngày nay, một ví dụ điển hình về phần mềm tự do và phát triển mã nguồn mở đó chính là hệ điều hành Linux Phiên bản đầu tiên của Linux được Linux Torvalds phát triển vào năm 1991 khi ông còn đang là sinh năm thứ 2 đại học Hensinki – Phần Lan và hoàn thành bản 1.0 vào năm 1994 Bộ phận này được phát triển và tung ra thị trường dưới bản quyền GNU GPL (đây là giấy phép phần mềm tự do phổ biến nhất do Richard Stallman viết cho dự án GNU) Do đó bất cứ ai cũng có thể tải về và xem mã nguồn của Linux
Kernel là trái tim của hệ điều hành Linux Nó quản lý các tài nguyên hệ thống Các tài nguyên này chính là các thiết bị trong Linux, ví dụ như: thiết bị lưu trữ dữ liệu, máy in, bộ nhớ, hệ thống quản lý file Kernel sẽ quyết định user nào sẽ sử dụng hệ thống, trong thời gian bao lâu và khi nào Nó sẽ chạy các chương trình của bạn (hoặc là cài đặt các file nhị phân) Kernel cũng chính là một bộ nhớ thường trú của Linux và thực hiện các tác vụ sau:
Trang 41.2 Shell là gì?
Như chúng ta đã biết, máy tính sử dụng ngôn ngữ nhị phân bao gồm 0 và 1 Trước đây để giao tiếp với máy tính, ta buộc lòng phải sử dụng ngôn ngữ nhị phân, điều này rất khó khăn, phức tạp và dễ gây nhầm lẫn Hệ điều hành cung cấp cho chúng ta một chương trình được biến đến dưới tên gọi Shell Shell tiếp nhận những câu lệnh, cấu trúc viết bằng tiếng Anh và dịch nó sang ngôn ngữ nhị phân
Mô hình shell hoạt động có thể hiểu như sau:
Có thể nói Shell chính là môi trường để người dùng tương tác với máy Shell cũng chính là một trình biên dịch ngôn ngữ lệnh và thực thi các lệnh truyền vào từ đầu vào chuẩn (bàn phím) hay một file Trong MS-DOS Shell chính là COMMAND.COM nhưng nó không linh hoạt và mạnh mẽ như Shell trong Linux
Trang 51.3 Phân loại Shell
Không có sự độc quyền trong shell, do đó bạn có thể tự do lựa chọn shell phù hợp với mình Đó có thể là một lợi thế nhưng cũng dẫn đến bất lợi nếu như lựa chọn một shell mà ta không biết gì về nó Dưới đây sẽ chỉ ra một số shell chính
1.3.1 Bourne Shell
Shell UNIX đầu tiên được biết đến chính là sh, viết tắt cho shell hoặc Bourne shell, được đặt theo tên người sáng lập ra sh: Steven Bourne Bourne shell đã trở thành một phần chuẩn trong UNIX trong vài thập kỷ Vì vậy, sh xuất hiện trên hầu hết các hệ
thống hỗ trợ UNIX hoặc các tập lệnh tương tự UNIX bao gồm Linux, Mac OS X
Một số đặc điểm của Bourne shell:
➢ Các đoạn script có thể thực thi như một lệnh thông qua tên file
➢ Cho phép cả đồng bộ và không đồng bộ khi thực thi các lệnh
➢ Hỗ trợ chuyển hướng xuất nhập và pipeline
➢ Cung cấp điều khiển luồng, các dấu nháy và hàm
➢ Không định kiểu đối với biến
➢ Cung cấp biến địa phương và biến toàn cục
➢ Các đoạn script không đòi hỏi phải được biên dịch trước khi thực thi
1.3.2 C Shell
C Shell được thiết kế bởi Bill Joy trường đại học California, nó có tên như vậy là
do rất nhiều các cú pháp tương tự với ngôn ngữ lập trình C Tuy nhiên thật khó có thể tìm ra được các điểm tương đồng, vì vậy đừng hy vọng các kỹ năng lập trình C có thể áp
Trang 6dụng hoàn toàn vào C Shell Điều đó là đúng, nhưng cũng có rất nhiều các lập trình viên
1.3.3 Korn Shell
Korn Shell đã phát triển và trở thành một phần không thể thiếu trong hệ thống BSD UNIX Khi AT&T (phòng thí nghiệm nổi tiếng có trụ sở chính tại đồi Murray – bang New Jersey) phát triển hệ thống UNIX V, các lập trình viên mới nhận ra rằng họ cần có một shell mới có thể đối chọi được với khả năng của C Shell Do C Shell phát triển theo hướng riêng và dần tách biệt với Bourne Shell nên C Shell buộc phải tạo những cầu nối mới có thể liên lạc được với những lệnh mới của Bourne Còn Korn Shell (viết tắt là ksh) có thể hỗ trợ được điều đó
1.3.4 Bash Shell
Qua quá trình sử dụng, người sử dụng muốn phải có một shell không những tương thích các đoạn script viết bằng Bourne Shell mà còn phải có đầy đủ các tính năng edit bằng dòng lệnh Ngoài ra người sử dụng cũng muốn có sự tự do trong vấn đề bản quyền Bash Shell (viết tắt của Bourne Again Shell) đáp ứng được tất cả những điều đó
Có thể thấy Bash là sự kết tinh những ưu điểm nổi bật của Korn Shell và C Shell
Đó là khả năng edit bằng dòng lệnh ở Korn Shell và khả năng tự hoàn thành lệnh của C Shell Đó chính là lý do mà Korn Shell chỉ phát triển ở những hệ thống UNIX V Hiện
Trang 7nay thì Bash Shell đã trở thành shell mặc định của các distro Linux cũng như của Mac
OS X
Trong khuôn khổ bài luận này, chúng ta chỉ tiến hành nghiên cứu Shell script trên Bash Shell Tuy nhiên ngay trong tên của Shell cũng đã cho thấy là một sự kế thừa từ Bourne nên các kiến thức này cũng là kiến thức chung của shell script
Trang 8Chương 2- Cú pháp ngôn ngữ shell script
2.1 Chương trình Hello World
Chúng ta hãy xem file Hello.sh dưới đây:
#!/bin/sh
# This is a short script to display “Hello” to
# screenecho “Hello World”
exit 0
Khi thực thi file Hello.sh sẽ được kết quả:
# chmod +x Hello.sh
# /Hello.shHello World
Chúng ta hãy cùng phân tích ví dụ này Trong shell, dấu # bắt đầu một dòng
comment Ở đây dòng 2 và dòng 3 là các dòng comment, tuy vậy dòng đầu tiên không phải comment dù nó cũng bắt đầu bằng dấu # Dòng đầu tiên là quy ước thông báo cho shell biết sử dụng shell sh để biên dịch file này Dòng 5 dùng để hiển thị một xâu ký tự sau echo ra màn hình Lệnh exit đảm bảo rằng script sau khi thực thi sẽ trả về mã lỗi, đây là cách mà hầu hết các chương trình nên làm Mặc dù mã lỗi trả về ít khi được dùng đến trong trường hợp thực hiện tương tác trực tiếp từ dòng lệnh Tuy nhiên, nhận biết mã trả về của một đoạn script sau khi thực thi lại thường rất có ích nếu triệu gọi scrit từ trong một kịch bản script khác Trong đoạn chương trình trên, lệnh exit trả về giá trị 0
Trang 9cho biết script thực thi thành công và thoát khỏi shell gọi nó Ta không cố tình bắt các lỗi xảy ra của những lệnh hệ thống trong trường hợp này.
Mặc dù chúng ta lưu tập tin với đuôi mở rộng là sh nhưng điều này là không bắt buộc Linux thường không sử dụng phần đuôi mở rộng của tập tin làm dấu hiện nhận dạng, vì vậy chúng ta có thể đặt đuôi mở rộng là bất kỳ tên nào, hoặc có thể không cần đuôi mở rộng (các script hệ thống thường làm theo cách này) Shell chỉ quan tâm đến
dòng đầu tiên của file ( #!/bin/sh) để quyết định đó là file gì.
2.2 Sử dụng biến
Trong hệ thống unix có 3 loại biến:
➢ Biến hệ thống (System Variable): biến được tạo bởi bản thân hệ điều hành,
các biến này được viết hoa hoàn toàn Một số biến hệ thống quan trọng được chỉ ra như bảng dưới đây:
Một số biến ở trên có thể sẽ thay đổi trên từng PC, ví dụ như biến
Trang 10$USERNAME – biến này trả về tên của tài khoản đang truy cập vào PC Đặc biệt lưu ý hạn chế thay đổi biến môi trường vì nó có thể gây ra một số tác hại không mong muốn.
➢ Biến người dùng tự định nghĩa:
Thông thường không cần phải khai báo biến trước khi sử dụng mà thay vào đó biến sẽ được tự động tạo và khai báo khi làn đầu tiên tên biến xuất hiện, chẳng hạn như trong phép gán Mặc định, tất cả các biến đều được khởi tạo và chứa giá trị kiểu chuỗi Ngay cả dữ liệu liệu đưa vào biến là một con số thì nó cũng được xem là định dạng chuỗi Shell và một vài lệnh tiện ích sẽ tự động chuyển chuỗi thành số để thực hiện phép tính khi có yêu cầu Bản thân hệ điều hành unix là hệ điều hành phân biệt chữ hoa chữ thường nên trong tên biến cũng có sự phân biệt đó
Bên trong các script của shell có thể lấy về nội dung của biến bằng cách dùng dấu
$ trước tên biến Tuy nhiên khi gán nội dung cho biến chúng ta không sử dụng ký tự $
trước tên biến Một đoạn ví dụ sau đây sẽ minh họa cho điều đó:
~> str=”Hello world”
~> echo $strHello world
Trong ngôn ngữ shell có quy định chặt chẽ về dấu cách trong các câu lệnh, đặc biệt trong phép gán không được có dấu cách
➢ Biến tham số (parameter variable):
Các biến tham số do shell tự quy định để lưu trữ giá trị các tham số truyền vào cho một lệnh Ví dụ: $1, $2 là các tham số truyền vào cho lệnh theo thứ tự từ trái sang phải Đặc biệt $0 trả về tên lệnh và $@ trả về danh sách các tham số truyền vào dưới
Trang 11dạng chuỗi Biến $# lưu danh sách tham số truyền vào dưới dạng 1 chuỗi, các tham số phân cách với nhau bởi biến $IFS, nếu $IFS=null thì biến $# tương đương với biến $@.
2.3 Phân biệt dấu nháy kép (“), dấu nháy đơn (') và dấu thực thi (`)
2.3.1 Dấu thực thi (`)
Dấu này dùng để thông báo shell cần phải thực hiện lệnh trong cặp dấu ` và ` Nó
tương đương với cấu trúc $(command) Ví dụ sau sẽ chỉ rõ điều đó:
~> echo `pwd`
/home/banhbaochay
~> echo $(pwd)/home/banhbaochay
2.3.2 Dấu nháy kép (“) và nháy đơn (')
Khác với dấu huyền ( ‘ ), những thông tin giữa hai dấu nháy (nháy đơn hoặc nháy kép) được coi là thông tin được sử dụng trong lệnh echo và sẽ được in ra màn hình hay được gán vào biến dạng xâu Như vậy, không thể viết các lệnh hệ thống giữa hai dấu nháy mà chỉ các để các xâu ký tự hay các biến Chúng ta xem xét những dòng ví dụ sau:
~> str=”World”
~> echo “Hello $str”
Hello World
~> echo 'Hello $str'Hello $str
Có thể dễ thấy sự khác biệt của hai dấu nháy đơn và nháy kép qua những dòng
Trang 12lệnh trên, đối với nháy kép (“), khi in ra sẽ được thực hiện với giá trị của biến sau dấu $ Đối với dấu nháy đơn (') thì sẽ in ra y nguyên như trong dòng văn bản Thông thường dấu nháy đơn ít được sử dụng nhưng lại rất tiện lợi khi muốn in y nguyên một dòng văn bản, đặc biệt là khi có các ký tự đặc biệt nh- $, \.
2.4 Cấu trúc trong ngôn ngữ shell script
2.4.1 Cấu trúc điều kiện
2.4.1.1 Cấu trúc if
Nền tảng cơ bản trong tất cả ngôn ngữ lập trình đó là khả năng kiểm tra điều kiện
và đưa ra quyết định rẽ nhánh thích hợp tùy theo điều kiện logic đúng hay sai Thực tế,
các script sử dụng lệnh [ và lệnh test để kiểm tra điều kiện logic rất nhiều Trong hầu hết các hệ thống UNIX và LINUX, hai lệnh này là tương đương Tuy nhiên lệnh [ hay
được sử dụng hơn do tính đơn giản và gần gũi với các ngôn ngữ lập trình khác
Cấu trúc điều kiện trong shell cũng tương tự như trong các ngôn ngữ bậc cao
khác, tức là cũng có các cấu trúc if, if else và if elif
if [ condition ]then
#script when result is truefi
hoặc
if [ condition ]then
#script when result is true
Trang 13#script 1elif [ condition2 ]
#script 2fi
Biểu thức condition có thể rơi vào 1 trong 3 kiểu dưới đây:
➢ Biểu thức so sánh chuỗi
➢ Biểu thức so sánh toán học
➢ Biểu thức kiểm tra tệp tin: do là ngôn ngữ chủ yếu can thiệp vào thư mục
và file trên hệ thống nên shell đã cung cấp sẵn các tùy chọn kiểm tra như -d, -e, -f, -g
Trang 14Cấu trúc case rất linh hoạt, nó cho phép người dùng so khớp nội dung của biến với một mẫu chuỗi pattern nào đó Nếu đúng sẽ thực hiện câu lệnh statements tương
ứng Chúng ta hãy cùng xem xét ví dụ sau:
#!/bin/shecho “Is it morning? Please answer yes or no”
read timeofdaycase $timeofday in
“yes” ) echo “Good morning” ;;
“no” ) echo “Good afternoon” ;;
“y” ) echo “Good morning” ;;
“n” ) echo “Good afternoon” ;;
* ) echo “Sorry, answer not recognised” ;;
esacexit 0
Cách chương trình làm việc như sau: Sau khi người dùng nhập câu trả lời, lệnh
case sẽ lấy nội dung của biến $timeofday so sánh vời từng chuỗi Điểm đặc biệt đó là khi gặp chuỗi thích hợp nó thực hiện lệnh sau dấu ( rồi kết thúc Nó tương tự như các ngôn ngữ khác nhưng luôn có lệnh break ở trong case Ký tự đại diện * cho phép so khớp với
mọi loại chuỗi * thường được xem như trường hợp so sánh đúng cuối cùng nếu tất cả
các mẫu so sánh trước đó thất bại Như vậy * giống như khóa default trong các ngôn ngữ
Trang 15khác Một phiên bản khác của ví dụ trên được chỉ ra dưới đây:
#!/bin/shecho “Is it morning? Please answer yes or no”
read timeofdaycase $timeofday in
“yes” | “y” | “YES” | “Yes” ) echo “Good morning” ;;
“n*” | “N*” ) echo “Good afternoon” ;;
* ) echo “Sorry, answer not recognised” ;;
esacexit 0
Đoạn script sử dụng nhiều mẫu so khớp trên cùng một dòng lệnh Trên thực tế điều này thường hay được sử dụng do làm code trở nên dễ đọc hơn
2.4.2 Cấu trúc điều khiển
Shell cũng như các ngôn ngữ khác cung cấp các cấu trúc điều khiển luồng như:for, while, until Bên cạnh sự khác biệt về mặt cú pháp, shell còn mang một đặc điểm rất riêng của mình
2.4.2.1 Vòng lặp for
Cấu trúc lệnh for như sau:
for variable in valuesdo
Trang 16Như đã nêu, biến variable sẽ nhận tập hợp các giá trị được nêu ra trong values Values có thể là một tập các giá trị hoặc là kết quả trả về của một lệnh.
Ta có 2 ví dụ để minh họa cho điều đó:
Trong ví dụ đầu tiên, tập hợp các giá trị sau từ khóa in phải được ngăn cách nhau bằng dấu cách Còn trong ví dụ thứ hai, shell sẽ thực hiện lệnh ls trước rồi chèn kết quả
Trang 17vào vị trí lệnh ls Lúc đó câu lệnh shell sẽ thành thế này:
~> for i in Documents downloads myfolder
2.4.2.2 Vòng lặp while và until
Hoàn toàn tương tự shell cũng cung cấp cấu trúc while như sau:
while conditiondo
#statementsdone
Cấu trúc until:
until conditiondo
#statementsdone
Cấu trúc while và cấu trúc until có một điểm khác biệt căn bản, đó là while thực thi statements khi condition trả về true, còn until dừng lại khi condition trả về true.
Một trong những ưu điểm nổi bật của shell đó chính là nó cho phép nối nhiều lệnh
và kết quả xuất ra theo nhiều cách khác nhau Bằng cách gõ các lệnh, chúng ta có thể thực hiện các tác vụ phức tạp bao gồm nhiều bước hoặc tinh chế kết quả kết xuất cho các tình huống đặc biệt Kỹ thuật phục vụ cho mục đích này chính là kỹ thuật pipeline trong shell sẽ được nhắc đến dưới đây
Trang 18Chương 3- Chuyển hướng xuất nhập
Các nhà thiết kế UNIX đã xây dựng nên một hệ thống với các đặc điểm sau:
➢ Mọi thứ trong hệ thống đều là file Các thiết bị đều được biểu diễn như là các file đặc biệt
➢ Mỗi một tiến trình chạy trong một môi trường riêng Môi trường đó bao gồm các file chuẩn cho input, output và error
➢ UNIX có rất nhiều các lệnh nhỏ, mỗi lệnh này được thiết kế để làm tốt nhất một tác vụ nào đấy Ưu điểm của nó là tiết kiệm bộ nhớ và giảm yêu cầu xử lý lên CPU
➢ Các lệnh này được thiết kế để xử lý dữ liệu từ dòng vào chuẩn stdin và đưa kết quả ra stdout
➢ Người dùng có thể kết hợp linh hoạt các lệnh này bằng cách tạo ra các lệnh pipelines
3.1 Làm việc với dòng vào chuẩn và dòng ra chuẩn
Tất cả mọi tiến trình trên UNIX hoặc hệ thống tương tự UNIX đều được cung cấp với 3 dòng chuẩn: stdin (dòng vào chuẩn), stdout (dòng ra chuẩn) và stderr (dòng lỗi chuẩn) Mặc định sẽ là:
➢ Standard input: đó là bàn phím hoặc là các file đối với script
➢ Standard output: đó là cửa sổ shell hoặc terminal khi chạy script
➢ Standard error: cũng giống như dòng ra chuẩn (cửa sổ shell hoặc
terminal)