Lap trinh java thiết lập môi trường lập trình java trên windows
Lập Trình C và Shell Trên Linux
-
Upload
jciver-jponest -
Category
Documents
-
view
487 -
download
3
description
Transcript of Lập Trình C và Shell Trên Linux
Môn học: Lập trình hệ thống
Phần: Hệ điều hành Linux Trang 1
Báo Cáo
LẬP TRÌNH HỆ THỐNG
Đề Tài: Hệ điều hành Linux
GVGD: Phạm Văn Khoa
SVTH: Đinh Văn Mạnh 09119059
Lương Văng Giang 09119010
Trần Minh Thanh 09119034
Đặng Quang Thịnh 09119039
Môn học: Lập trình hệ thống
Phần: Hệ điều hành Linux Trang 2
Mục lục
PHẦN I. LẬP TRÌNH SHELL .......................................................................................... 4
I. Bash shell ................................................................................................................ 4
1. Sử dụng biến ........................................................................................................ 4
2. Cấu trúc điều khiển ........................................................................................... 10
3. Danh sách AND (&&) ......................................................................................... 16
4. Danh sách Or ....................................................................................................... 18
5. Tài liệu here ......................................................................................................... 18
II. Ngôn ngữ C shell ..................................................................................................... 19
1. Biến ..................................................................................................................... 19
2. Cấu trúc điều kiện If .......................................................................................... 20
3. Câu lệnh while: .................................................................................................. 20
4. Nhiều điều kiện - AND/OR ................................................................................ 21
5. Câu lệnh foreach:............................................................................................... 21
6. Câu lệnh while: .................................................................................................. 22
7. Switch … case ................................................................................................... 22
8. Tham số dòng lệnh: .......................................................................................... 23
III. Trình bày sự khác nhau trong cấu trúc điều khiển giữa 2 loại shell này ............ 23
1. Mệnh đề If .......................................................................................................... 23
2. Dạng If … else .................................................................................................... 24
3. Dạng else - if ....................................................................................................... 24
4. Mệnh đề case ...................................................................................................... 25
5. Mệnh đề for ........................................................................................................ 26
6. Mệnh đề while .................................................................................................... 26
7. Mệnh đề Until .................................................................................................... 27
PHẦN II. LẬP TRÌNH C TRÊN LINUX ....................................................................... 34
A. Thư viện liên kết trên Linux ................................................................................ 34
a. Thư viện liên kết tĩnh......................................................................................... 34
b. Thư viện liên kết động ....................................................................................... 42
B. Makefile: sử dụng trong biên dịch mã nguồn. .................................................... 50
1. Vì sao ta phải dùng Makefile? ........................................................................... 50
Môn học: Lập trình hệ thống
Phần: Hệ điều hành Linux Trang 3
2. ........................................................ 53
3. Ví dụ Demo sử dụng Makefile ........................................................................... 55
Môn học: Lập trình hệ thống
Phần: Hệ điều hành Linux Trang 4
PHẦN I. LẬP TRÌNH SHELL
Các shell trên unix/linux - Sh ( Bourne) : shell nguyên thủy áp dụng cho Unix
- Csh, Tcsh, zsh : Dòng shell sử dụng cấu trúc lệnh của C làm ngôn ngữ kịch
bản. Được tạo ra đầu tiên bởi Bia Joy. Là Shell thông dụng thứ hai sau Bash
Shell.
- Bash : shell chủ yếu của Linux. Ra đời từ dự án GNU.bash (viết tắt của
Bourne Again Shell ) có lợi điểm là mã nguồn được công bố rộng rãi. Các bạn
có thể tải về và sử dụng miễn phí tại www.gnu.org
- Rc : Shell mở rộng của csh với nhiều tương thích với ngôn ngữ C hơn. Rc
cũng ra đời từ dự án GNU
Chú ý : Tuy bash là shell là shell chuẩn được các nhà phân phối sử dụng phổ biến
trong Linux nhưng các ví dụ về lập trình sẽ sử dụng ngôn ngữ và lệnh của shell sh
bởi vì shlà shell nguyên thủy, có thể chạy trên cả Unix. Bằng lệnh file ta sẽ thấy
trong hầu hết các bản Linux hiện nay sh chỉ là liên kết dẫn đến bash mà thôi.
Ví dụ : $file / bin / sh
/bin/sh : symbolic link to bash
Điều này có nghĩa là bash hoàn toàn có thể diễn dịch và điều khiển các lệnh của shell
sh.
I. Bash shell
Ở phần này ta sẽ tìm hiểu về :
- Biến: kiểu chuỗi, kiểu số, tham số và biến môi trường.
- Điều kiện : kiểm tra luận lý Boolean bằng shell
- Điều kiện chương trình: if, elif, for, while, until, case
1. Sử dụng biến
- Thường thì ta không cần phải khai báo biến trước khi sử dụng. Thay vào đó
biến sẽ 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à mang trị
kiểu string.Tương tự như HĐH và ngôn ngữ C, cú pháp Shell phân biệt chữ
hoa chữ thường, biến mang tên foo, Foo, FOO là 3 biến khác nhau.
- Bên trong Script của Shell, bạn có thể lấy về nội dung của biến bằng cách
dùng dấu $ đặt trước tên biến. Để hiển thị nội dung của biến, bạn có thể dùng
Môn học: Lập trình hệ thống
Phần: Hệ điều hành Linux Trang 5
lệnh echo. Khi gán nội dung cho biến bạn không cần sử dụng ký tự $ . Ví dụ
trên dòng lệnh, bạn có thể gán nội dung và hiển thị biến như sau :
$ xinchao = hello
$echo $xinchao
Hello
$ xinchao = “I am here”
$echo $xinchao
I am here
$ xinchao =12+1
$echo $xinchao
12+1
Lưu ý : sau dấu = không được có khoảng trắng. Nếu gán nội dung chuỗi có khoảng
trắng cho biến, cần bao bọc chuỗi bằng dấu “ “.
1.1 Các ký tự đặc biệt
1.1.1 Các ký tự chuyển hướng vào/ ra
Ký hiệu Ý nghĩa
> Đầu ra hướng tới
>> Nối vào nội dung của
< Lấy đầu vào từ <
<< Đầu vào là ở đây
2> Đầu ra báo lỗi sẽ hướng vào
2>> Đầu ra báo lỗi hướng và ghi thêm vào
1.1.2 Các ký tự kiểm soát tiến trình
• Dấu & ( ampersand) : đặt một tiến trình vào chế độ chạy nền. Với & chương
trình sẽ tự chạy và shell quay ngay về tương tác với người dùng, trả lại dấu nhắc
ngay. Tiến trình nền có nhiều cách để kiểm soát.
• Dấu ( ; ) Dùng để nhóm một số lệnh lại, phân cách bởi ;
• Dấu ` ` (backqoutes) Dấu thay thế.
Bất kỳ lệnh nào xuất hiện trong dấu nháy sẽ được thực hiện trước và kết quả của
lệnh đó sẽ thay thế đầu ra chuẩn (stdout) trước khi lệnh trong dòng lệnh thực hiện
• Pipeline
Môn học: Lập trình hệ thống
Phần: Hệ điều hành Linux Trang 6
Shell cho phép kết quả thực thi một lệnh, kết hợp trực tiếp đầu vào của lệnh khác mà
không cần xử lý trung gian
cmd & Đặt lệnh cmd chạy nền
cmd1 ; cmd2 Chạy cmd1 trước sau đó chạy cmd2
(cmd) Thực hiện cmd trong một shell con
`cmd` Đầu ra cmd sẽ thay cho đầu ra của lệnh trong dòng lệnh
Cmd1\cmd2 Nối đầu ra của cmd1 vào đầu vào của cmd2
• Dấu “ ” hay „ ‟
Ví dụ dấu “” hoặc „ ‟
#!/bin/bash
myvar="Hi there"
echo $myvar
echo "message : $myvar"
echo 'message : $myvar'
echo "message :\$myvar"
echo Enter some text
read myvar
echo '$myvar' now equals $myvar
exit 0
Kết xuất khi thực thi script :
Hi there
Message : Hi there
Message: $myvar
Message: $myvar
Enter some text
Hello world
$myvar now equals Hello World
Môn học: Lập trình hệ thống
Phần: Hệ điều hành Linux Trang 7
Cách chương trình làm việc: Biến myvar được tạo ra và khởi gán giá trị
chuỗi Hi there. Nội dung của biến sau đó được hiển thị bằng lệnh echo trong các trường
hợp bọc chuỗi bằng dấu nháy kép, nháy đơn và dấu hiển thị đắc biệt . Tóm lại nếu muốn
thay thế nội dung biến trong một chuỗi cần bọc chuỗi bằng nháy kép. Nếu muốn hiển
thị toàn bộ nội dung của chuỗi,hãy dùng nháy đơn.
1.2 Biến môi trường
Khi trình shell khởi động nó cung cấp sẵn một số biến được khai báo và gán
giá trị mặc định. Chúng được gọi là các biến môi trường. Các biến này thường được
viết hoa để phân biệt với các biến do người dùng tự định nghĩa ( thường là ký tự
không hoa ). Nội dung các biến này thường tùy vào thiết lập của hệ thống sử dụng.
Danh shell của các biến môi trường là khá nhiều, nhưng nhìn chung nên nhớ một số
biến môi trường chủ yếu sau:
Biến môi trường Ý nghĩa
$HOME Chứa nội dung của thư mục chủ
$PATH Chứa danh shell các đường dẫn
$PS1 Dấu nhắc hiển thị trên dòng lệnh. Thường là $user
$SP2 Dấu nhắc thứ cấp, thông báo người dùng nhập thêm thông tin trước khi
lệnh thực hiện. Thường là dấu >
$IFS Dấu phân cách các trường hợp trong danh shell chuỗi
$0 Chứa tên chương trình gọi trên dòng lệnh
$# Số tham số truyền trên dòng lệnh
$$ Mã tiến trình của shell script thực thi
Mỗi môi trường mà user đăng nhập chứa một số danh shell biến môi trường dùng
cho mục đích riêng. Có thể dùng lệnh export của shell .
1.3 Biến tham số (parameter variable)
- Nếu cần tiếp nhận tham số trên dòng lệnh để xử lý, có thể dùng thêm các biến
môi trường sau:
Biến tham số Ý nghĩa
$1,$2,$3 Vị trí và nội dung của các tham số trên dòng lệnh theo thứ
tự trái – phải
Môn học: Lập trình hệ thống
Phần: Hệ điều hành Linux Trang 8
S* Danh shell của tất cả các tham số trên dòng lệnh. Chúng
được lưu trong một chuỗi duy nhất phân cách bằng ký tự
đầu tiên quy định trong biến $IFS
S@ Danh shell các tham số được chuyển thành chuỗi. Không
sử dụng dấu phân cách của biến IFS
Ví dụ sau sẽ minh họa một số cách đơn giản xử lý và truy xuất biến môi
trường .
- Ví dụ: Try_var.sh
#!/bin/bash
salutation="Hello"
echo $salutation
echo "The program $0 is now running"
echo "The second parameter was $2"
echo "The first parameter was $1"
echo "The parameter list was $*"
echo "The user's home directory is $HOME"
echo "Please enter a new greeting"
read salutation
echo $salutation
echo "The script is now complete"
exit 0
Lưu tên tập là try_var.sh, đổi thuộc tính thực thi x cho tập tin bằng lệnh :
$chmod+x try_var.sh
Khi chạy try_varsh từ dòng lệnh,bạn sẽ nhận được kết quả của kết xuất như
sau :
$./try_var.sh foo bar baz
Hello
The program./try_var.sh is now running
The second parameter was bar
Môn học: Lập trình hệ thống
Phần: Hệ điều hành Linux Trang 9
The first parameter was foo
The parameter list was foo bar baz
The user‟s home directory is/home/xyz
Please enter a new greeting
Xin chao!
Xin chao!
The script is now complete
Ví dụ dấu “” hoặc „ ‟
#!/bin/bash
myvar="Hi there"
echo $myvar
echo "message : $myvar"
echo 'message : $myvar'
echo "message :\$myvar"
echo Enter some text
read myvar
echo '$myvar' now equals $myvar
exit 0
Kết xuất khi thực thi script :
Hi there
Message : Hi there
Message: $myvar
Message: $myvar
Enter some text
Hello world
$myvar now equals Hello World
Cách chương trình làm việc: Biến myvar được tạo ra và khởi gán giá trị
chuỗi Hi there. Nội dung của biến sau đó được hiển thị bằng lệnh echo trong
Môn học: Lập trình hệ thống
Phần: Hệ điều hành Linux Trang 10
các trường hợp bọc chuỗi bằng dấu nháy kép, nháy đơn và dấu hiển thị đắc
biệt \. Tóm lại nếu muốn thay thế nội dung biến trong một chuỗi cần bọc chuỗi
bằng nháy kép. Nếu muốn hiển thị toàn bộ nội dung của chuỗi,hãy dùng nháy
đơn.
2. Cấu trúc điều khiển
2.1. Lệnh if
- Lệnh If tuy đơn giản nhưng được sử dụng nhiều nhất . If kiểm tra điều kiện
đúng hoặc sai để thực thi biểu thức thích hợp.
If condition
Then
Statements
Else
Statements
Ví dụ : Đoạn script sau sử dụng if tùy vào câu trả lời của bạn mà đưa ra lời chào
thích hợp : if_control.sh
#!/bin/bash
Echo” Is it morning? Please answer yes or no”
Read timeofday
If [$timeofday = “yes” ]; then
Echo” Good morning”
Else
Echo “ Good afternoon”
Fi
Exit 0
Kết quả của scrift
$./If_control.sh
Is it morning? Please answer yes or no
Yes
Good morning
$
2.2. Lệnh Elif
Môn học: Lập trình hệ thống
Phần: Hệ điều hành Linux Trang 11
- Trong ví dụ If_control.sh ở trên có rất nhiều phát sinh. Tất cả các câu trả lời
khác với “yes” đều có nghĩa là “no”. Chúng ta có thể khắc phục điều này bằng
cách sử dụng cấu trúc điều khiển elif. Mệnh đề này cho phép kiểm tra điều
kiện lần thứ 2 bên trong else. Script dưới đây có thể hoàn chỉnh hơn, có thể in
ra thông báo lỗi nếu người dùng nhập không đúng “yes” hoặc “no”
Ví dụ: Elif_control.sh
#!/bin/bash
Echo “Is it morning? Please answer yes or no”
Read timeofday
If [$timeofday = ”yes”]; then
Echo”good morning”
Elif[$timeofday= “no”]; then
Echo” Good afternoon”
Else
Echo “ Sorry, $timeofday not recognized. Enter yes or no”
Fi
Exit 0
Chú ý : Tương tự như ví dụ if_control.sh nhưng ta sử dụng them elif để kiểm
tra trường hợp người dùng không nhập “no”. Thông báo lỗi được in ra và mã
lỗi trả về bằng lệnh exit là 1. Trường hợp hoặc “yes” hoặc “no” được nhập
vào, mã lỗi trả về sẽ là 0.
2.3. Lệnh For
- Sử dụng for để lặp lại một số lần với các giá trị xác định. Phạm vi lặp có thể
nằm trong một tập hợp chuỗi chỉ định tường minh bởi chương trình hay là kết
quả trả về từ một biến hoặc biểu thức khác.
Cú pháp:
For variable in values
Do
Statements
Môn học: Lập trình hệ thống
Phần: Hệ điều hành Linux Trang 12
Done
Ví dụ: for.sh
#!/bin/bash
rm -rf fred*
echo > fred1
echo > fred2
mkdir fred3
echo > fred4
for file in fred*
do
if [ -d "$file" ]; then
break;
fi
done
echo first directory fred was $file
exit 0
2.4. Lệnh Case
- Lệnh Case có cách sử dụng hơi phức tạp hơn các lệnh đã học. Cú pháp của
lệnh case như sau :
Case variable in
Pattern[ | partten]….) statement ; ;
Pattern[ | partten]….) statement ; ;
….
Esac
- Mặc dù nhìn khá khó hiểu , nhưng lệnh case rất linh động. Case cho phép thực
hiện so khớp nội dung của biến với một chuỗi mẫu pattern nào đó. Khi một
mẫu được so khớp thì lệnh statement tương ứng sẽ được thực hiện. Hãy lưu ý
đặt dấu ;; phía sau mỗi mệnh đề so khớp pattern, shell dùng dấu hiệu này để
nhận dạng mẫu pattern so khớp tiếp theo mà biến cần thực hiện.
Môn học: Lập trình hệ thống
Phần: Hệ điều hành Linux Trang 13
- Việc cho phép so khớp nhiều mẫu khác nhau làm case trở nên thích hợp cho
việc kiểm tra nhập liệu của người dùng.
Sau đây là ví dụ : case1.sh
#!/bin/bash
echo "Is it morning? Please answer yes or no"
read timeofday
case "$timeofday" in
"yes") echo "Good Morning";;
"no" ) echo "Good Afternoon";;
"y" ) echo "Good Morning";;
"n" ) echo "Good Afternoon";;
* ) echo "Sorry, answer not recognised";;
esac
exit 0
- Cách thực hiện: Sauk hi người dùng nhập vào 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. Khi gặp chuỗi thích hợp nó
sẽ thực thi lệnh sau dấu ) và kết thúc (không tiếp tục so khớp với các mẫu
khác) . 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 các mẫu so sánh trước đó
thất bại. Bạn có thể xem * là mệnh đề default trong lệnh switch của C hay
case….else của Pascal.
- Ngoài cách trên, ta có thể kết hợp chung các mẫu so khớp với nhau khiến cho
case ngắn gọn hơn như sau: case2.sh
#!/bin/bash
echo "Is it morning? Please answer yes or no"
read timeofday
case "$timeofday" in
"yes" | "y" | "Yes" | "YES" ) echo "Good Morning";;
"n*" | "N*" ) echo "Good Afternoon";;
* ) echo "Sorry, answer not recognised";;
esac
Môn học: Lập trình hệ thống
Phần: Hệ điều hành Linux Trang 14
exit 0
Script trên sử dụng nhiều mẫu so khớp trên một dòng so sánh của lệnh case . Các
mẫu này có ý nghĩa tương tự nhau và yêu cầu thực thi cùng một lệnh nếu điều kiện
đúng xảy ra. Cách viết này thực tế thường dùng và dễ đọc hơn cách viết thứ nhất.
Mặc dù vậy. hãy tìm hiểu case ở ví dụ sau, case sử dụng lệnh exit để trả về mã lỗi
cho từng trường hợp so sánh mẫu đồng thời case sử dụng cách so sánh tắt bằng ký tự
đại diện.
Ví dụ: Case3.sh
#!/bin/bash
echo "Is it morning? Please answer yes or no"
read timeofday
case "$timeofday" in
"yes" | "y" | "Yes" | "YES" )
echo "Good Morning"
echo "Up bright and early this morning?"
;;
"[nN]*" )
echo "Good Afternoon"
;;
* )
echo "Sorry, answer not recognised"
echo "Please answer yes or no"
exit 1
;;
esac
exit 0
- Cách thực hiện : Trong trường hợp “no” ta dùng ký tự đại diện * thay thế cho
tất cả ký tự n và N. Điều này có nghĩa là nx hay Nu…đều có nghĩa là „no‟. Ở
ví dụ trên ta đã thấy cách đặt nhiều lệnh trong cùng một trường hợp so khớp .
Exit 1 cho biết người dùng không chọn yes và no. Exit 0 biết người dùng đã
chọn yes , no theo yêu cầu:
Có thể không cần đặt ;; ở mẫu so khớp cuối cùng trong
Môn học: Lập trình hệ thống
Phần: Hệ điều hành Linux Trang 15
lệnh case (phía trước esac) , vì không còn mẫu so khớp nào cần thực hiện nữa.
Không như C yêu cầu phải đặt lệnh break ở mỗi mệnh đề case, shell không đòi hỏi
điều này, nó biết tự động chấm dứt khi lệnh case tương ứng đã tìm được mẫu thỏa
mãn.
- Để làm case trở nên mạnh mẽ và so sánh được nhiều trường hợp hơn, có thể
giới hạn các ký tự so sánh theo cách sau : [yy] | [Yy] [Ee] [Ss] , khi đó y, Y
hay yes, YES…đều được xem là yes. Cách này đúng hơn là dùng ký tự thay
thế toàn bộ * trong trường hợp [nN]*.
2.5 Lệnh while
Lệnh while cho phép thực hiện lặp vô hạn khi điều kiện kiểm tra vẫn còn đúng
Cú pháp:
While condition do
Statements
Done
Ví dụ : password.sh
#!/bin/sh
Echo “enter password”
Read trythis
While [“$trythis” !- “secret”]; do
Echo “ sorry, try again”
Ready trythis
Done
Exit 0
Kết xuất của script
$./password.sh
Enter password
Abc
Sorry, try again
Secret
$
Môn học: Lập trình hệ thống
Phần: Hệ điều hành Linux Trang 16
Lệnh while liên tục kiểm tra nội dung biến $trythis , yêu cầu nhập lại
dữ liệu bằng lệnh read một khi $trythis vẫn chưa bằng với chuỗi “secret”.
2.6. Lệnh until
Cú pháp lệnh:
Until condition
Do
Statements
Done
Lệnh until tương tự lệnh while nhưng điều kiện kiểm tra bị đảo ngược lại.
Vòng lặp sẽ bị dừng nếu điều kiện kiểm tra là đúng.
Ví dụ sau sử dụng lệnh until để chờ user đăng nhập
Ví dụ until_user.sh
#!/bin/sh
Echo “Locate for user…”
Until who | grep “$1” > dev/null
Do
Sleep 60
Done
Echo –e\\a
Echo “***** $1 has just logged in ******”
Exit 0
Lệnh who đọc danh shell các user đăng nhập vào hệ thống, chuyển
danh shell này cho grep bằng cơ chế đường ống ( | ) . Lệnh grep lọc ra tên user
theo biến môi trường $1 hiện có nội dung là chuỗi xyz. Một khi lệnh grep lọc
ra dữ liệu , nó sẽ truyền ra vùng tập tin rỗng/dev/null và trả lại giá trị null,
lệnh until kết thúc.
3. Danh sách AND (&&)
Môn học: Lập trình hệ thống
Phần: Hệ điều hành Linux Trang 17
- Danh shell AND cho phép thực thi một chuỗi cạnh kề nhau, lệnh sau chỉ thực
hiện khi lệnh trước đã thực thi và trả về mã lỗi thành công. Cú pháp sử dụng
như sau : Statement1 && statement2 && statement3 &&….
- Bắt đầu từ bên trái statement1 sẽ thực hiện trước, nếu trả về true thì
statement2 tiếp tục được gọi. Nếu statement2 trả về false thì shell chấm dứt
danh shell AND và ngược lại statement3 sẽ được gọi ….Toán tử && dùng
để kiểm tra kết quả trả về của statement trước đó. Kết quả trả về của AND sẽ
là true nếu tất cả các lệnh statement đều được gọi thực thi. Ngược lại là false.
- Ví dụ sau dùng lệnh toauch file_one (để kiểm tra file_one tồn tại hay chưa,
nếu chưa thì tạo mới) tiếp đến rm file_two. Sau cùng danh shell AND sẽ kiểm
tra xem các file có đồng thời tồn tại hay không để đưa ra thông báo thích hợp.
Ví dụ and.sh
#!/bin/bash
touch file_one
rm -f file_two
if [ -f file_one ] && echo "hello" && [ -f file_two ] && echo "there"
then
echo -e "in if"
else
echo -e "in else"
fi
exit 0
Chạy thử script trên bạn sẽ nhận được kết quả như sau :
$./and_list.sh
Hello
In else
- Cách chương trình làm việc : Lệnh touch và rm đảm bảo rằng file_one tồn tại
và file_two không có. Trong danh shell biểu thức if, && sẽ gọi lệnh [-f
file_one ] trước. Lệnh này thành công vì touch đã tạo sẵn file_one. Lệnh echo
tiếp tục được gọi luôn trả về trị true nên theo lệnh tiếp theo [-f file_two] thi
hành. Do file_two không tồn tại nên echo “there” không được gọi. Toàn bộ
Môn học: Lập trình hệ thống
Phần: Hệ điều hành Linux Trang 18
biểu thức trả về giá trị false (vì các lệnh trong danh shell không được thực thi
hết). Do if nhận trị false nên echo trong mệnh đề else của lệnh if được gọi.
4. Danh sách Or
Danh sách OR cũng tương tự với AND là thực thi một dãy các lệnh trả về true
thì việc thực thi dừng lại. Cú pháp như sau :
Statement1||statement2||statement3 &&….
Ví dụ: or_list.sh
#!/bin/sh
Rm –f file_one
If [ -f file_one] || echo “hello” || echo “there”
Then
Echo “ in if”
Else
Echo “ in else”
Fi
Exit 0
Cách chương trình làm việc: File_one đầu tiên được loại bỏ để đảm
bảo lệnh if tiếp theo không tìm thấy nó. Lệnh [-f file_one ] trả về false vì
file_one không tồn tại. Lệnh echo tiếp theo trong chuỗi danh shell OR sẽ được
gọi in ra hello. Do echo luôn trả về true nên echo tiếp theo không được gọi.
Bởi vì trong danh shell OR có một lệnh trả về true nên toàn bộ biểu thức sẽ là
true. Kết quả cuối cùng là echo trong if được gọi để in ra chuỗi “in if”.
5. Tài liệu here
- Unix và Linux cung cấp cơ chế tự động hóa mô phỏng việc nhập hõ vào từ
bàn phím bằng tài liệu here ( here document). Ta để sẵn các phím hay chuỗi
cần gõ trong một tập tin và chuyển hướng tập tin này cho lệnh cần thực thi.
Nó sẽ tiếp nhận và đọc nội dung tập tin như những gì đã gõ từ bàn phím.
- Ví dụ, khi gõ lệnh cat , nó sẽ chờ nhập dữ liệu gõ vào từ bàn phím. Nếu khi
script thực thi không có mặt người dùng ở đó thì sao? Quá trình tự động của
Môn học: Lập trình hệ thống
Phần: Hệ điều hành Linux Trang 19
script sẽ dừng lại chờ đến khi ta xuất hiện để gõ dữ liệu vào. Cơ chế tài liệu
here giúp thực hiện tự động nhập liệu như sau : ví dụ cat_here
#! /bin/bash
cat > test.txt <<!YOURLABEL!
Hello
This is
here document
!YOURLABEL!
Kết quả khi thực thi cat_here.sh, tệp test.txt được tạo ra. Với nội dung là chuỗi Hello
This is…ta không cần phải dùng tay nhập dữ liệu cho lệnh cat.
Tài liệu here yêu cầu đặt cú pháp ở giữa nhãn bắt đầu và nhãn kết thúc. Trong ví dụ
trên nhãn bắt đầu là !YOURLABEL! ( Lưu ý đến ký tự << ở đầu dùng để cho biết
nơi bắt đầu của tài liệu here) ,nhãn kết thúc là !YOURLABEL! . Dấu ! hai bên nhãn
YOURLABEL chỉ để dễ dàng nhận ra nhãn mà thôi, trong trường hợp nội dung dữ
liệu của chuỗi YOURLABEL thì cặp ! ! cũng dùng để phân biệt riêng tên nhãn của
người dùng.
II. Ngôn ngữ C shell
Cấu trúc C Shell: C Shell cung cấp ngôn ngữ dòng lệnh tương tự như ngôn ngữ lập trình
C. Ngôn ngữ C shell chứa cấu trúc: nhập và xuất, toán tử điều kiện, quản lý tập tin và
định nghĩa biến...Nếu bạn đã làm quen với các ngôn ngữ lập trình cấp thấp, thì lập trình
shell sẽ rất đơn giản.
1. Biến
Lệnh cơ bản để khai báo biến trong C shell là set. Ví dụ:
set name = "Henri"
=> sẽ khởi tạo biến name chứa giá trị "Henri".
set users = (George Frank Mary Heloise Hartsell)
=> sẽ khởi tạo biến có kiểu dữ liệu wordlist (mảng chuỗi), bây giờ chúng ta có thể truy
cập giá trị này bằng index của chúng.
@ count = 0
=> khởi tạo biến kiểu integer.
Môn học: Lập trình hệ thống
Phần: Hệ điều hành Linux Trang 20
Ghi chú: lệnh set chỉ được sử dụng cho các biến shell. Biến môi trường như DISPLAY,
EDITOR...phải được khai báo bằng lệnh setenv.
2. Cấu trúc điều kiện If
a. If...then
Cho phép người dùng thực thi một lệnh hoặc một nhóm lệnh chỉ khi điều kiện phù hợp.
Cấu trúc như sau:
if (condition(s))
then
command(s)
endif
Điều kiện trong dấu ngoặc được tính trước và trả về giá trị 0 (false) hoặc 1 (true). Chỉ
khi điều kiện là true các lệnh mới được thực thi.
b. If...then...else
Cấu trúc này cho phép người dùng xác định nhóm lệnh "default" - thực thi nếu điều kiện
sau từ khóa if là false, ngược lại nhóm lệnh giữa điều kiện if và từ khóa else sẽ thực thi.
if (condition(s))
then
command group 1
else
command group 2
end if
3. Câu lệnh while:
Có lúc bạn cần thực thi một lệnh lặp đi lặp lại cho đến khi điều kiện phù hợp. Nếu cấu
trúc if...then không đáp ứng được, bởi vì điều kiện của nó chỉ được tính toán một lần.
Đặt điều kiện trong foreach cũng không đáp ứng được hoặc khó coi, bởi vì số vòng lặp
vô hạn. Chúng ta cần một vòng lặp xoay vòng không hạn định cho đến khi giá trị của
điều kiện là false. Trong trường hợp này, chúng ta sử dụng câu lệnh while:
while (condition)
statements
end
Môn học: Lập trình hệ thống
Phần: Hệ điều hành Linux Trang 21
4. Nhiều điều kiện - AND/OR
- Toán tử AND là && - điều kiện ghép là true nếu cả tất cả điều kiện là true.
- Toán tử OR là || và điều kiện ghép sẽ là true nếu một trong tất cả điều kiện là true.
Toán tử kiểm tra tập tin:
operator filename
Ví dụ:
Chạy lệnh dựa vào điều kiện tập tin "mail.log" có tồn tại hay không.
if (-e mail.log) then
cat new.log >> mail.log
endif
Sử dụng biến thay thế cho tên tập tin:
set file_to_remove = .pine-interrupted-mail
if (-z $file_to_remove) then
rm $file_to_remove
endif
=> kiểm tra file có tên chứa trong biến có chiều dài là 0 hay không, nếu đúng là xóa file
đó đi.
Toán tử Ý nghĩa
-d tập tin là thư mục?
-e tập tin tồn tại?
-f plain file?
-o quyền chủ sở hữu?
-r quyền đọc?
-w quyền ghi?
-x quyền thực thi?
-z tập tin có chiều dài là 0?
Để đảo ngược giá trị của toán tử này, sử dụng ! trước toán tử trong dấu ngoặc (ví dụ như
! -z filename).
5. Câu lệnh foreach:
Môn học: Lập trình hệ thống
Phần: Hệ điều hành Linux Trang 22
Câu lệnh foreach cho phép bạn thực thi một lệnh hoặc một nhóm lệnh cho mỗi file mà
tên của nó phù hợp với mẫu xác định. Ví dụ: tạo script xóa file rỗng và file có tên là core
trong thư mục home của bạn.
#!/bin/csh
foreach dudfile(/home/users1/hansel/*)
if (-z $dudfile || $dudfile == "core") then
rm $dudfile
endif
end
6. Câu lệnh while:
Có lúc bạn cần thực thi một lệnh lặp đi lặp lại cho đến khi điều kiện phù hợp. Nếu cấu
trúc if...then không đáp ứng được, bởi vì điều kiện của nó chỉ được tính toán một lần.
Đặt điều kiện trong foreach cũng không đáp ứng được hoặc khó coi, bởi vì số vòng lặp
vô hạn. Chúng ta cần một vòng lặp xoay vòng không hạn định cho đến khi giá trị của
điều kiện là false. Trong trường hợp này, chúng ta sử dụng câu lệnh while:
while (condition)
statements
end
7. Switch … case
Chọn lựa từ danh sách:
Giả sử bạn viết một chương trình menu. Người dùng chọn số từ 1 đến 6. Một hành động
sẽ được thực hiện phụ thuộc vào những gì người dùng chọn. Chúng ta có thể sử dụng
một chuỗi câu lệnh if...then...else if...then...else if...then..., nhưng rất khó coi và khó đọc
nếu chúng ta debug chương trình. Thay vào đó chúng ta có thể sử dụng chức năng
switch...case.
#!/bin/csh
echo -n "Please enter your first name: "
set uname = $<
switch ($uname)
case [Gg]eorge:
Môn học: Lập trình hệ thống
Phần: Hệ điều hành Linux Trang 23
cat /messages/George
breaksw
case [Mm]ary:
cat /messages/Mary
breaksw
case [Ss]andy:
cat /messages/Sandy
breaksw
default:
cat /messages/Goodbye
exit 1
endsw
8. Tham số dòng lệnh:
Nếu bạn muốn script của bạn chạy giống như các lệnh UNIX khác - cho phép người
dùng chuyển vào tên tập tin hoặc chuỗi, thì bạn sẽ cần sử dụng khả năng tham số của C
shell. Trong C shell có biến đặc biệt là argv. Biến này có kiểu dữ liệu wordlist, mỗi từ
trên dòng lệnh là một phần tử trong mảng. Ví dụ chúng ta đã viết script wrap cho phép
thực hiện một số chức năng trên file, chúng ta gọi script với cấu trúc:
wrap infile outfile
Trong script này giá trị argv[1] sẽ là infile và giá trị argv[2] sẽ là outfile. Chúng ta có thể
truy cập các giá trị này như sau:
#!/bin/csh
if (!-e $argv[1]) then
echo "Error: file $argv[1] does not exist."
exit 2
endif
III. Trình bày sự khác nhau trong cấu trúc điều khiển giữa
2 loại shell này
Cấu trúc điều khiển gồm If, Elif , For, While, Until, Case
1. Mệnh đề If
Môn học: Lập trình hệ thống
Phần: Hệ điều hành Linux Trang 24
bash csh
if [bieu_thuc]
then
cau_lenh
...
fi
if (bieu_thuc)
then
cau_lenh
...
endif Nếu biểu thức bieu_thuc được đánh giá là Đúng thì (các) câu lệnh cau_lenh sẽ được
thực hiện, còn không thì chương trình sẽ bỏ qua và thực hiện ngay câu lệnh phía sau fi
hoặc endif.
Nếu chỉ có một câu lệnh được thực hiện trong if thì Csh còn có một dạng đơn giản hơn
là :
if (bieu_thuc) cau_lenh
2. Dạng If … else
bash Csh
if [bieu_thuc]
then
cau_lenh
...
else
cau_lenh
...
fi
if (bieu_thuc) then
cau_lenh
...
else
cau_lenh
...
endif
Dạng này mở rộng dạng đơn giản nói trên ở chỗ: nếu bieu_thuc là Sai thì (các)
câu lệnh cau_lenh sau else sẽ được thực hiện.
3. Dạng else - if
Nếu sau else còn tiến hành kiểm tra một điều kiện bieu_thuc2 nữa thì người ta phải đưa
thêm một mệnh đề if nữa vào trong khối mệnh đề else.
bash Csh
if [bieu_thuc]
then cau_lenh
...
elsif [bieu_thuc2]
then cau_lenh
... else
if (bieu_thuc) then cau_lenh
...
else if (bieu_thuc2) then cau_lenh
... else
caulenh
... endif
Môn học: Lập trình hệ thống
Phần: Hệ điều hành Linux Trang 25
cau_lenh
... fi
Ví dụ 1: Ví dụ sau sẽ thực hiện kiểm tra tệp tai_lieu có nằm trong thư mục hiện tại
không và in kết quả ra màn hình.
- Đối với bash và pdksh:
if [ -f tai_lieu]
then
echo "Co tệp tai_lieu trong thu mục hien thoi" else
echo "Khong tim thay tệp tai_lieu trong thu muc hien thoi"
fi
- Đối với csh (lưu ý phải có ký tự # ở đầu chương trình) :
#
if ( { -f tai_lieu } ) then
echo "Co tệp tai_lieu trong thu muc hien thoi" else
echo "Khong tim thay tệp tai_lieu trong thu muc hien thoi"
endif
4. Mệnh đề case
Mệnh đề case cho phép so một mẫu (chuỗi ký tự) với nhiều mẫu khác nhau và thực hiện
đoạn mã tương ứng với mẫu trùng khớp. Cú pháp của nó như sau:
bash Cshell
case mau in
mau1)
cau_lenh
...
;;
mau2)
cau_lenh
...
;;
...
*)
cau_lenh
...
switch (mau)
case mau1:
cau_lenh
...
Breaksw
case mau2:
cau_lenh
...
breaksw
...
default:
cau_lenh
...
Môn học: Lập trình hệ thống
Phần: Hệ điều hành Linux Trang 26
;;
esac
breaksw
endsw
Trong đó, mau được so sánh lần lượt với các mẫu mau1, mau2... Nếu có một mẫu trùng
khớp thì (các) câu lệnh tương ứng sẽ được thực hiện cho đến khi gặp hai dấu chấm phảy
(;;) bash hoặc breaksw (csh). Nếu không có mẫu nào trùng khớp thì (các) câu lệnh trong
khối * bash hoặc default (csh) được thực hiện.
5. Mệnh đề for
Mệnh đề for thực hiện các câu lệnh trong vòng lặp với một số lần nhất định. Nó có các
dạng sau:
Bash Csh
for bien in danh_sach
do
cau_lenh
...
done
foreach bien (danh_sach)
cau_lenh
...
end
Trong dạng này, mệnh đề for thực hiện mỗi vòng lặp cho mỗi mục trong danh sách
danh_sach. Danh sách này có thể là một biến chứa các từ ngăn cách nhau bởi một dấu
cách hoặc cũng có thể được gõ trực tiếp các từ đó vào dòng lệnh. Mỗi vòng lặp, biến
bien được gán lần lượt một mục (từ) trong danh sách cho đến hết danh sách.
6. Mệnh đề while
Mệnh đề while thực hiện đoạn chương trình bên trong chừng nào mà biểu thức đã cho
còn là Đúng. Cú pháp của nó như sau:
bash Csh
while bieu_thuc
do
menh_de
...
done
while (bieu_thuc)
menh_de
...
end
Môn học: Lập trình hệ thống
Phần: Hệ điều hành Linux Trang 27
7. Mệnh đề Until
Cú pháp của mệnh đề until giống với mệnh đề while. Điểm khác biệt là ở chỗ, mệnh đề
while thực hiện vòng lặp chừng nào biểu thức điều kiện còn Đúng, còn mệnh đề until
thực hiện vòng lặp chừng nào biểu thức điều kiện còn Sai. Cú pháp của nó trong bash
như sau :
until bieu_thuc do
cau_lenh
... done
Csh không có mệnh đề này.
IV. BÀI TẬP SHELL
Yêu cầu : Viết một chương trình shell tương tác với hệ thống Linux với yêu cầu:
chương trình shell tạo một menu lựa chọn cho phép
1. hiển thị tên các nhóm có trong hệ thống và các user tồn tại trong từng nhóm
2. hiển thị tên và mật khẩu của tất cả các user tồn tại trong hệ thống
3. hiển thị thời gian đăng nhập của từng user vào hệ thống
4. hiển thị các thông tin về phần cứng của hệ thống
5. kiểm tra xem các phần mềm: pico, vi, openssh server, gcc, tftp, nfs đã cài đặt trên
hệ thống hay chưa? Nếu phần mềm nào chưa cài thì sẽ tự động cài đặt cho hệ thống
Thực hiện: Dưới đây là script thực hiện yêu cầu trên.
#!/bin/bash
until [ "$verify" = n ]
do
echo "Lựa chọn các tính năng theo số thứ tự "
echo "1) hiển thị tên các nhóm có trong hệ thống và các user tồn tại trong từng
nhóm "
echo "2) hiển thị tên và mật khẩu của tất cả các user tồn tại trong hệ thống "
echo "3) hiển thị thời gian đăng nhập của từng user vào hệ thống "
echo "4) hiển thị các thông tin về phần cứng của hệ thống "
Môn học: Lập trình hệ thống
Phần: Hệ điều hành Linux Trang 28
echo "5) kiểm tra xem các phần mềm: pico, vi, openssh server, gcc, tftp, nfs đã
cài đặt trên hệ thống hay chưa? Nếu phần mềm nào chưa cài thì sẽ tự động cài đặt
cho hệ thống "
echo "6) Quit"
echo "Please enter your choice"
read pattern
case $pattern in
1) echo "Hiển thị lựa chọn 1"
echo "Danh sách tên nhóm và các user"
cat /etc/passwd | cut -d: -f1,5
# hien thi ten nhom va user trong tung nhom
;;
2) echo " Hiển thị lựa chọn 2"
echo "Tên và mật khẩu các user"
sudo cat /etc/shadow
# login - login name
# password - password in encrypted form, which is 13 to 24 characters long.
# Daysince - Days since [month, day, year] that the password was changed
# Daysafter - Days before the password may be changed
# Daysmust - Days after which the password must be changed
# dayswarn - Days before the password will expire ( A warning to the user)
# daysexpire - Days after the password expires that the account is disabled
# daysince - Days since [month, day, year]that the account is disabled.
# reserved - Reserved field.
;;
3) echo " Hiển thị lựa chọn 3"
echo "Thời gian đăng nhập vào hệ thống của từng user"
last
;;
4) echo " Hiển thị lựa chọn 4"
Môn học: Lập trình hệ thống
Phần: Hệ điều hành Linux Trang 29
echo "Thông tin phần cứng"
sudo lshw -short
;;
5) echo "Hiển thị lựa chọn 5 "
echo "Kiểm tra cài đặt phần mềm"
sudo dpkg -l 'pico'
sudo dpkg -l 'vim-common'
sudo dpkg -l 'openssh-server'
sudo dpkg -l 'gcc'
sudo dpkg -l 'tftp'
sudo dpkg -l 'nfs-common'
sudo dpkg -l 'nfs-client'
echo "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
echo "Cài đặt pico"
sudo apt-get install pico
echo "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
echo "Cài đặt vi"
sudo apt-get install vim-common
echo "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
echo "Cài đặt ssh-server"
sudo apt-get install openssh-server
echo "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
echo "Cài đặt gcc"
sudo apt-get install gcc
echo "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
echo "Cài đặt tftp"
Môn học: Lập trình hệ thống
Phần: Hệ điều hành Linux Trang 30
sudo apt-get install tftp
echo "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
echo "Cài đặt nfs-common"
sudo apt-get install nfs-common
echo "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
echo "Cài đặt nfs-client"
sudo apt-get install nfs-client
;;
6)
exit 0
;;
esac;
echo "Do you want to continue your choice (y/n)?"
read verify
done
Kết quả :
Menu hiển thị các lựa chọn
Lựa chọn 1: Hiển thị các nhóm và user trong từng nhóm
Môn học: Lập trình hệ thống
Phần: Hệ điều hành Linux Trang 31
Lựa chọn 2: Hiển thị tên và mật khẩu từng user
Mật khẩu đã được mã hóa.
Lựa chọn 3: Hiển thị thời gian đăng nhập từng user
Môn học: Lập trình hệ thống
Phần: Hệ điều hành Linux Trang 32
Lựa chọn 4: Hiển thị thông tin phần cứng
Lựa chọn 5: Kiểm tra các gói phần mềm và cài đặt
- Dưới đây là kiểm tra các gói phần mềm đã cài đặt hay
chưa
Môn học: Lập trình hệ thống
Phần: Hệ điều hành Linux Trang 33
- Nếu chưa được cài đặt thì hệ thống sẽ tự động cài đặt
Môn học: Lập trình hệ thống
Phần: Hệ điều hành Linux Trang 34
- Hệ thống sẽ hỏi bạn có muốn cài đặt tiếp phần mềm
không.
PHẦN II. LẬP TRÌNH C TRÊN LINUX
A. Thư viện liên kết trên Linux
Hình thức đơn giản nhất của thư viện là tập hợp các tập tin “.o” do trình biên dịch tạo ra ở
bước biên dịch với tùy chọn -c.
a. Thư viện liên kết tĩnh
i. Khái niệm thư viện liên kết tĩnh
Thư viện liên kết tĩnh là các thư viện khi liên kết trình biên dịch sẽ lấy
toàn bộ mã thực thi của các hàm trong thư viện đưa vào chương trình
chính.
ii. Tạo thư viện liên kết tĩnh
Gồm 3 bước cơ bản:
Bước 1. Viết các hàm cho thư viện.
Bước 2. Tạo các file đối tượng từ các hàm thư viện vừa viết.
Môn học: Lập trình hệ thống
Phần: Hệ điều hành Linux Trang 35
Bước 3. Nén các file đối tượng vừa tạo thành một file thư viện “.a”,
tiếp đầu ngữ “lib”.
Ví dụ: Tạo một thư viện liên kết tĩnh, chứa các hàm với chức năng như sau:
- nhap3so: cho nhập vào 3 số thực.
- gptb2: giải phương trình ax^2+bx+c=0, (a # 0)
- nhapchuoi: cho nhập vào chuỗi kí tự.
- xulychuoi: định dạng cơ bản chuỗi kí tự.
Bước 1. Viết các hàm cho thư viện
gedit nhap3so.c
//code nhap3so.c
#include<stdio.h>
void nhap3so()
{
float a,b,c;
printf("Ham nhap 3 so thuc : \n");
printf("Nhap cac he so : \n");
printf("Nhap a:\n");
scanf("%f",&a);
printf("Nhap b:\n");
scanf("%f",&b);
printf("Nhap c:\n");
scanf("%f",&c);
}
//end code nhap3so.c
gedit gptb2.c
//code gptb2.c
#include<stdio.h>
#include<math.h>
void gptb2()
Môn học: Lập trình hệ thống
Phần: Hệ điều hành Linux Trang 36
{
float a,b,c;
float x,x1,x2;
float delta=b*b-4*a*c;
if(delta>0)
{
x1=(-b+sqrt(delta))/(2*a);
x2=(-b-sqrt(delta))/(2*a);
printf("Phuong trinh co 2 nghiem phan biet:\n");
printf("x1=%.2f , x2=%.2f ",x1,x2);
}
else if(delta==0)
{
x=-b/(2*a);
printf("Phuong trinh co nghiem kep:\n");
printf("x1=x2=%.2f ",x);
}
else
{
printf("Phuong trinh vo nghiem !\n");
}
}//end code gptb2.c
gedit nhapchuoi.c
//code nhapchuoi.c
#include <string.h>
#include <stdio.h>
char s[100];
void nhapchuoi()
{
Môn học: Lập trình hệ thống
Phần: Hệ điều hành Linux Trang 37
puts("Ham nhap chuoi ki tu : \n");
puts("Nhap vao mot chuoi ki tu: \n");
while(getchar() != '\n');
gets(s);
}
//end code nhapchuoi.c
gedit xulychuoi.c
//code xulychuoi.c
#include<string.h>
#include<ctype.h>
#include<stdio.h>
char s[100];
void xulychuoi()
{
int len_s,i,j;
len_s=strlen(s);
printf("Do dai chuoi la %d\n",len_s);
printf("\n");
////////////////////////////
for(i=0;i<len_s;i++)
{
if(s[i]>='A'&&s[i]<='Z')
s[i]=s[i]+32;
}
puts("Chuyen doi chuoi thanh chu thuong\n");
puts(s);
printf("\n");
/////////////////////////////
for(j=0;j<len_s;j++)
Môn học: Lập trình hệ thống
Phần: Hệ điều hành Linux Trang 38
{
if(j==0)
s[0]=toupper(s[0]);
if(s[j]==32)
s[j+1]=toupper(s[j+1]);
}
puts("Viet hoa ki tu dau trong chuoi:\n");
puts(s);
printf("\n");
/////////////////////////////
for(j=0;j<len_s;j++)
{
if(s[j]>='a'&&s[j]<='z')
s[j]=s[j]-32;
}
puts("Chuyen doi chuoi thanh chu hoa:\n");
puts(s);
printf("\n");
}
//end code xulychuoi.c
Bước 2. Tạo các file đối tượng “.o” từ các hàm vừa viết.
gcc -c nhap3so.c gptb2.c xulychuoi.c nhapchuoi.c
Bước 3. Nén các file đối tượng vừa tạo thành một file thư viện “.a”, tiếp đầu
ngữ “lib”. Vd: libstatic.a
ar cvr libstatic.a nhap3so.o gptb2.o nhapchuoi.o xulychuoi.o
Ứng dụng thư viện liên kết tĩnh libstatic.a :
1. Viết chương trình giải phương trình bậc hai.
2. Viết chương trình tổng hợp:
- Giải phương trình bậc hai
Môn học: Lập trình hệ thống
Phần: Hệ điều hành Linux Trang 39
- Xử lý chuỗi cơ bản
1. Chương trình giải phương trình bậc hai
a. Tạo file tiêu đề “.h” - khai báo thuộc tính cho các hàm sử dụng trong
chương trình.
gedit header_gpt.h
//code header_gpt.h
void nhap3so();
void gptb2();
//end code header_gpt.h
b. Tạo file và viết code chương trình chính
gedit main_gpt.c
//code main_gpt.c
#include "header_gpt.h"
void main(void)
{
nhap3so();
gptb2();
}
//end code main_gpt.c
c. Biên dịch chương trình chính liên kết với thư viện tĩnh libstatic.a
gcc main_gpt.c -o main_gpt libstatic.a -lm
d. Thực thi chương trình
./main_gpt
2. Chương trình tổng hơp
- Giải phương trình bậc 2: ax^2+bx+c =0 (a#0)
- Xử lý chuỗi cơ bản
a. Tạo file tiêu đề “.h”- khai báo thuộc tính cho các hàm sử dụng trong
chương trình
gedit header.h
//code header.h
Môn học: Lập trình hệ thống
Phần: Hệ điều hành Linux Trang 40
void nhap3so();
void gptb2();
void nhapchuoi();
void xulychuoi();
//end code header.h
b. Tạo file và viết code chương trình chính
gedit main_th.c
//code main_th.c
#include <stdio.h>
#include <string.h>
#include "header.h"
void main(void)
{
int choice;
char exit;
do
{
printf("Menu Chuong Trinh\n");
printf("1) Xu ly chuoi ky tu\n");
printf("2) Giai phuong trinh ax^2+bx+c=0\n");
printf("3) Thoat chuong trinh\n");
printf("Lua chon yeu cau : \n");
scanf("%d",&choice);
switch(choice)
{
case 1: nhapchuoi();
xulychuoi();
break;
case 2: nhap3so();
gptb2();
Môn học: Lập trình hệ thống
Phần: Hệ điều hành Linux Trang 41
break;
case 3:
break;
default : printf("Phai nhap 1, 2 hoac 3\n");
};
printf("Thoat chuong trinh ? (y/n)\n");
while(getchar() != '\n');
scanf("%c",&exit);
}while(exit == 'n');
}
//end code main_th.c
c. Biên dịch chương trình chính liên kết với thư viện tĩnh libstatic.a
gcc main_th.c -o main_th libstatic.a -lm
d. Thực thi chương trình
./main_th
Ưu điểm: Chương trình sử dụng thư viện liên kết tĩnh có thể chạy độc lập với thư
viện sau khi được biên dịch – chạy được trên các máy tính khác nhau.
Nhược điểm:
- Tốn không gian ổ đĩa:
o Toàn bộ mã thực thi của các hàm trong thư viện sẽ được nhúng vào file
thực thi của chương trình chính.
o Nhiều chương trình khác nhau không thể cùng dùng chung một thư viện
duy nhất.
o Có những hàm trong thư viện mà chương trình chính không dùng đến
cũng được liên kết với chương trình chính khi biên dịch.
- Hạn chế trong việc sửa đổi, nâng cấp thư viện liên kết tĩnh và các chương
trình sử dụng thư viện liên kết tĩnh đó:
Môn học: Lập trình hệ thống
Phần: Hệ điều hành Linux Trang 42
o Khi muốn sửa đổi hoặc nâng cấp thư viện thì phải thay đổi hoặc thêm
mã nguồn cho các hàm trong thư viện, dẫn đến việc phải biên dịch lại
từ đầu mã nguồn để tạo ra file thư viện “.a”.
o Chương trình sử dụng thư viện liên kết tĩnh nếu muốn tận dụng những
tính năng mới của thư viện thì cũng phải được biên dịch lại.
b. Thư viện liên kết động
i. Khái niệm thư viện liên kết động
Thư viện liên kết động là thư viện mà các hàm trong thư viện không
được trực tiếp đưa vào chương trình lúc biên dịch và liên kết.
Trình liên kết chỉ lưu thông tin tham chiếu đến các hàm trong thư viện.
Vào lúc chương trình thực thi, hệ điều hành sẽ nạp các chương trình
liên kết cần tham chiếu vào bộ nhớ.
ii. Tạo thư viện liên kết động
Gồm 3 bước cơ bản:
Bước 1. Viết các hàm cho thư viện.(tương tự như thư viện liên
kết tĩnh)
Bước 2. Tạo các file đối tượng “.o” từ các hàm vừa viết để đưa
vào thư viện liên kết động ( sử dụng gcc với tùy chọn -fpic).
Bước 3. Tạo file thư viện liên kết động (“.so”, tiếp đầu ngữ
“lib”) , từ các file đối tượng vừa tạo, sử dụng gcc với tùy chọn -
shared.
Ví dụ: Tạo một thư viện liên kết động, chứa các hàm với chức năng như sau:
- nhap3so: cho nhập vào 3 số thực.
- gptb2: giải phương trình ax^2+bx+c=0, (a # 0)
- nhapchuoi: cho nhập vào chuỗi kí tự.
- xulychuoi: định dạng cơ bản chuỗi kí tự.
Bước 1. Viết các hàm cho thư viện.
gedit nhap3so.c
//code nhap3so.c
Môn học: Lập trình hệ thống
Phần: Hệ điều hành Linux Trang 43
#include<stdio.h>
float a,b,c;
void nhap3so()
{
printf("Ham nhap 3 so thuc : \n");
printf("Nhap cac he so : \n");
printf("Nhap a:\n");
scanf("%f",&a);
printf("Nhap b:\n");
scanf("%f",&b);
printf("Nhap c:\n");
scanf("%f",&c);
}
//end code nhap3so.c
gedit gptb2.c
//code gptb2.c
#include<stdio.h>
#include<math.h>
float a,b,c;
void gptb2()
{
float x,x1,x2;
float delta=b*b-4*a*c;
if(delta>0)
{
x1=(-b+sqrt(delta))/(2*a);
x2=(-b-sqrt(delta))/(2*a);
printf("Phuong trinh co 2 nghiem phan biet:\n");
printf("x1=%.2f , x2=%.2f ",x1,x2);
Môn học: Lập trình hệ thống
Phần: Hệ điều hành Linux Trang 44
}
else if(delta==0)
{
x=-b/(2*a);
printf("Phuong trinh co nghiem kep:\n");
printf("x1=x2=%.2f ",x);
}
else
{
printf("Phuong trinh vo nghiem !\n");
}
}
//end code gptb2.c
gedit nhapchuoi.c
//code nhapchuoi.c
#include <string.h>
#include <stdio.h>
char s[100];
void nhapchuoi()
{
puts("Ham nhap chuoi ki tu : \n");
puts("Nhap vao mot chuoi ki tu: \n");
while(getchar() != '\n');
gets(s);
}
//end code nhapchuoi.c
gedit xulychuoi.c
//code xulychuoi.c
Môn học: Lập trình hệ thống
Phần: Hệ điều hành Linux Trang 45
#include<string.h>
#include<ctype.h>
#include<stdio.h>
char s[100];
void xulychuoi()
{
int len_s,i,j;
len_s=strlen(s);
printf("Do dai chuoi la %d\n",len_s);
printf("\n");
////////////////////////////
for(i=0;i<len_s;i++)
{
if(s[i]>='A'&&s[i]<='Z')
s[i]=s[i]+32;
}
puts("Chuyen doi chuoi thanh chu thuong\n");
puts(s);
printf("\n");
/////////////////////////////
for(j=0;j<len_s;j++)
{
if(j==0)
s[0]=toupper(s[0]);
if(s[j]==32)
s[j+1]=toupper(s[j+1]);
}
puts("Viet hoa ki tu dau trong chuoi:\n");
puts(s);
printf("\n");
Môn học: Lập trình hệ thống
Phần: Hệ điều hành Linux Trang 46
/////////////////////////////
for(j=0;j<len_s;j++)
{
if(s[j]>='a'&&s[j]<='z')
s[j]=s[j]-32;
}
puts("Chuyen doi chuoi thanh chu hoa:\n");
puts(s);
printf("\n");
}
//end code xulychuoi.c
Bước 2. Tạo các file đối tượng “.o” từ các hàm vừa viết để đưa vào thư viện
liên kết động ( sử dụng gcc với tùy chọn -fpic).
gcc -c -fpic nhap3so.c gptb2.c nhapchuoi.c xulychuoi.c
Bước 3. Tạo file thư viện liên kết động (“.so”, tiếp đầu ngữ “lib”) , từ các file
đối tượng vừa tạo, sử dụng gcc với tùy chọn -shared.
gcc -shared nhap3so.o gptb2.o nhapchuoi.o xulychuoi.o -o libdynamic.so
(trong đó “libdynamic.so” là tên thư viện liên kết động)
Ứng dụng thư viện liên kết động libdynamic.so:
1. Viết chương trình giải phương trình bậc hai.
2. Viết chương trình tổng hợp:
- Giải phương trình bậc hai
- Xử lý chuỗi cơ bản
1. Chương trình giải phương trình bậc hai
a. Tạo file và viết code chương trình chính
gedit main_gpt2.c
//code main_gpt.c
void main(void)
{
Môn học: Lập trình hệ thống
Phần: Hệ điều hành Linux Trang 47
nhap3so();
gptb2();
}
//end code main_gpt2.c
b. Biên dịch chương trình sử dụng thư viện liên kết động libdynamic.so
gcc main_gpt2.c -o main_gpt2 -L. -ldynamic -lm
Tùy chọn -L. -ldynamic : chỉ ra cho trình liên kết tìm đến thư viện dynamic trong thư mục
hiện hành để lưu thông tin tham chiếu các hàm dùng trong chương trình chính.
c. Chạy file thực thi vừa tạo
- Định đường dẫn biến môi trường chỉ đến thư mục hiện hành – nơi chứa thư
viện libdynamic.so cần tham chiếu.
LD_LIBRARY_PATH=.:
export LD_LIBRARY_PATH
- Chạy file thực thi:
./main_gpt2
2. Chương trình tổng hợp
- Xử lý chuỗi kí tự cơ bản nhập từ bàn phím
- Giải phương trình bậc hai: ax^2+bx+c=0, (a#0)
a. Tạo file và viết code chương trình chính
gedit main_th2.c
//code main_th2.c
#include <stdio.h>
#include <string.h>
void main(void)
{
int choice;
char exit;
do
{
Môn học: Lập trình hệ thống
Phần: Hệ điều hành Linux Trang 48
printf("Menu Chuong Trinh\n");
printf("1) Xu ly chuoi ky tu\n");
printf("2) Giai phuong trinh ax^2+bx+c=0\n");
printf("3) Thoat chuong trinh\n");
printf("Lua chon yeu cau : \n");
scanf("%d",&choice);
switch(choice)
{
case 1: nhapchuoi();
xulychuoi();
break;
case 2: nhap3so();
gptb2();
break;
case 3:
break;
default : printf("Phai nhap 1, 2 hoac 3\n");
};
printf("Thoat chuong trinh ? (y/n)\n");
while(getchar() != '\n');
scanf("%c",&exit);
}while(exit == 'n');
}
//end code main_th2.c
b. Biên dịch chương trình sử dụng thư viện liên kết động libdynamic.so
gcc main_th2.c -o main_th2 -L. -ldynamic -lm
c. Chạy file thực thi vừa tạo
./main_th2
Ưu điểm:
- Tiết kiệm không gian ổ đĩa:
Môn học: Lập trình hệ thống
Phần: Hệ điều hành Linux Trang 49
o File thực thi của chương trình chính không chứa mã thực thi của các
hàm trong thư viện.
o Nhiều chương trình khác nhau có thể cùng dùng chung một thư viện
duy nhất.
- Chương trình sử dụng thư viện liên kết động không phải được biên dịch lại mà
vẫn có thể sử dụng những tính năng mới của thư viện (trong trường hợp thư
viện đó được sửa đổi, nâng cấp).
Khuyết điểm:
- Chương trình sử dụng thư viện liên kết động không thể chạy độc lập với thư
viện – chương trình phụ thuộc hoàn toàn vào thư viện.
- Hạn chế khi muốn sửa đổi hoặc nâng cấp: Khi muốn sửa đổi hoặc thêm hàm
cho thư viện, vẫn phải thực hiện lại các bước như khi tạo thư viện ban
đầu(tương tự thư viện liên kết tĩnh).
Kết luận về ưu, nhược điểm trong việc lập trình ngôn ngữ C trên Linux sử dụng thư viện
liên kết động và liên kết tĩnh :
Kích thước file thực thi:
Xem lại các chương trình trong 2 video trước, cùng một mã nguồn nhưng việc
sử dụng loại thư viện liên kết khác nhau dẫn đến kích thước file thực thi khác
nhau: chương trình sử dụng thư viện liên kết tĩnh luôn có kích thước file lớn
hơn chương trình sử dụng thư viện liên kết động.
File thực thi Thư viện liên kết tĩnh Thư viện liên kết động
main_gpt 7.2KB 7.0KB
main_th 7.5KB 7.2KB
Khả năng độc lập của chương trình thực thi với thư viện:
o Chương trình sử dụng thư viện liên kết tĩnh có khả năng chạy độc lập với thư
viện sau khi được biên dịch.
o Chương trình sử dụng thư viện liên kết động phụ thuộc vào thư viện, không
thể chạy độc lập với thư viện.
Khả năng chỉnh sửa, thay đổi của chương trình ứng dụng:
Môn học: Lập trình hệ thống
Phần: Hệ điều hành Linux Trang 50
o Do tính độc lập của chương trình sử dụng thư viện liên kết tĩnh nên nếu muốn
chỉnh sửa chương trình ứng dụng thì cần phải biên dịch lại chương trình cùng
với thư viện mà nó liên kết.
o Chương trình sử dụng thư viện liên kết động có thể tận dụng trực tiếp ngay
những sự thay đổi của thư viện mà nó liên kết, không cần phải được biên dịch
lại.
Nói tóm lại, ta có bảng sau:
Chương trình ứng dụng Thư viện liên kết tĩnh Thư viện liên kết động
Kích thước Lớn Nhỏ
Tính độc lập Có Không
Khả năng chỉnh sửa, nâng cấp Hạn chế Hỗ trợ
Tùy vào mục đích, khả năng, quy mô cũng như phạm vi chương trình ứng dụng mà
người lập trình cần cân nhắc trong việc lựa chọn sử dụng loại thư viện liên kết cho phù hợp
nhất.
B. Makefile: sử dụng trong biên dịch mã nguồn.
Câu lệnh make thường được ít người dùng quan tâm đến. Thông thường câu lệnh này
và Makefile nằm trong nhóm mã nguồn hỗ trợ biên dịch và liên kết mã nguồn trong file thực
thi.
Tuy nhiên nó còn có thể được sử dụng để thực hiện nhiều tính năng khác ngoài việc
xử lý mã nguồn.
Makefile là một chuỗi lệnh thực thi, làm việc trên các phần phụ của file mục tiêu. Ví
dụ, bạn có thể chạy lệnh make install và lệnh này sẽ kiểm tra cập nhật những đối tượng
được yêu cầu trước tiên, như mục tiêu compile và các thành phần phụ của nó. Điều này làm
cho lệnh make trở thành một lệnh rất linh hoạt. Điều này cũng có nghĩa bạn có thể sử dụng
nó với nhiều file ngoại trừ file mã nguồn; bạn có thể sử dụng Makefile để copy file (cục bộ
hay từ xa), kiểm soát phiên bản, xóa file, hay những lệnh khác có thể sử dụng khi xử lý file.
Trong bài này chúng ta tập trung vào mục tiêu sử dụng Makefile trong biên dịch mã
nguồn đối với lập trình C.
1. Vì sao ta phải dùng Makefile?
Các chương trình quá lớn:
Môn học: Lập trình hệ thống
Phần: Hệ điều hành Linux Trang 51
- Có rất nhiều dòng code
- Các thành phần phức tạp.
- Nhiều hơn 1 người lập trình
Các vấn đề:
- Các file dài khó để quản lí (cho cả người lập trình và máy).
- Mọi thay đổi đề đòi hỏi sự biên dịch dài. Nhiều người lập trình không thể chỉnh
sửa các file đòng thời.
Giải pháp: chia project(dự án/công trình) thành các file.
Mục tiêu:
- Phân chia tốt các thành phần
- Tối thiểu sự biên dịch khi có gì đó thay đổi.
- Dễ dàng bảo trì cấu trúc project, sự phụ thuộc và sự sáng tạo.
. Đ
Makefile
- ,
- :
CC=gcc # the C compiler is gcc
CFLAGS=-g -Wall -I/usr/include/libxml2
LIBS=-lxml2
tut_prog: main.o aux.o
$(CC) $(LIBS) main.o aux.o -o tut_prog
main.o: main.c
$(CC) -c $(CFLAGS) main.c
aux.o: aux.c
$(CC) -c $(CFLAGS) aux.c
.
N)
, CFLAGS, LIBS
Môn học: Lập trình hệ thống
Phần: Hệ điều hành Linux Trang 52
.
:
+CC „gcc‟
CXX ++‟
CPP $(cc) –e‟
RM –f‟
CFLAGS
LDFLAGS
Môn học: Lập trình hệ thống
Phần: Hệ điều hành Linux Trang 53
2.
target: prerequisites….
command
...
...
- target thường là tên của file được tạo ra bởi chương trình, hoặc cũng có thể là
các chỉ định để thực thi một hoặc một loạt tác vụ nào đó. Các target không
được bắt đầu bằng dấu '.'
- prerequisite là file hoặc các file đầu vào hoặc phụ thuộc để tạo ra target. target
thường phụ thuộc vào các file này, khi các file này thay đổi (do chỉnh sửa mã
nguồn->thời gian lưu cửa file bị thay đổi) thì target sẽ được biên dịch lại.
- command là lệnh hoặc tập lệnh mà trình make sẽ thực thi. Một rule (quy tắc)
có thể có nhiều lệnh (command), mỗi lệnh thường được viết trên một dòng.
Chú ý: trước mỗi dòng lệnh bạn cần phải có dấu tab. Dấu '\' ở cuối dòng để
quy định dòng dưới tiếp theo thực chất cũng là dòng trên, vì dòng trên dài quá,
nên chúng ta có thể ngắt xuống dưới bằng dấu này.
Các biến:
Các biến được dùng để rút gọn, khai báo có dạng sau:
var=text1text2..textn
Khi sử dụng để tham chiếu ta dùng theo dạng $(var) .
.
-
- .
:
all
check
clean
distclean
dist (tar.gz)
install )
uninstall
1. Sử dụng các biến trong Makefile
Môn học: Lập trình hệ thống
Phần: Hệ điều hành Linux Trang 54
Tạo ra Makefile: Nội dung của Makefile của project như sau:
Code:
USER_DIR=..
LIB_DIR=$(USER_DIR)/libraries
MAIN_FILE_DIR=$(USER_DIR)/mainFile
INC=-I$(LIB_DIR)
#compiler
CC=gcc
FLAG= -Wall-g-W
#source
STUB=$(LIB_DIR)/ipc.c $(LIB_DIR)/person.c
#nameofmainfile
MAIN_FILE_NAME=sample1
#object
OBJECT= ipc.o person.o
#The Target
run: ready code
$(CC)$(INC)$(FLAG)$(MAIN_FILE_NAME).o$(OBJECT)-o run
ready:
$(CC)$(INC)$(FLAG) -c $(STUB)
code:
$(CC) $(INC) $(FLAG) -c $(MAIN_FILE_DIR)/$(MAIN_FILE_NAME).c
clean
rm -rf *.o run
Những từ viết in hoa đó là các biến môi trường (such as: USER_DIR, GXX, FLAG,
MAIN_FILE_NAME,....) sau dấu = của các biến môi trường là nội dung được gán
cho các biến
Vídụ:
USER_DIR=.. <-- biến USER_DIR với nội dung là ".."
LIB_DIR= $(USER_DIR)/libraries <-- biến LIB_DIR với nội dung là "../libraries"
Môn học: Lập trình hệ thống
Phần: Hệ điều hành Linux Trang 55
Một số lời khuyên khi tạo Makefile:
- Bạn nên tạo ra biến môi trường:
Ở ví dụ trên nếu không dùng biến môi trường mà viết thẳng trong các target dòng
lệnh luôn, tức là Makefile của trở thành:
Code:
run: ready code
gcc -I../libraries -Wall -g -W sample1.o ipc.o person.o -o run
ready:
gcc -I../libraries -Wall -g -W -c ../libraries/ipc.c ../libraries/person.c
code:
gcc -I../libraries -Wall -g -W -c ../mainFile/sample1.c
clean:
rm -rf *.o run
thì Makefile vẫn hoạt động bình thường tuy nhiên make file này chỉ có thể dịch cho
mỗi file sample1.c hoặc nếu muốn thay thành sample2.c thì phải thay cả ở run,code.
- Nên tạo ra Target có chức năng tương tự target clean:
Khi làm việc với project lớn thì việc tạo clean khá quan trọng vì khi gọi nó sẽ
xóa đi những gì được gọi là rác trong quá trình build như là những file object
hoặc file executable cũ chẳng hạn.
3. Ví dụ Demo sử dụng Makefile
Viết chương trình cho phép nhập vào một số nguyên, yêu cầu xuất ra màn hình số
vừa nhập là chẵn hay lẻ ?
Các bước thực hiện:
Tạo file main.c // chương trình chính
Code:
#include <stdio.h>
#include "header.h"
void main(void)
{
int num;
printf("Nhap vao mot so: \n");
Môn học: Lập trình hệ thống
Phần: Hệ điều hành Linux Trang 56
scanf("%d",&num);
if(odd_even(num))
printf("%d la so chan \n",num);
else
printf("%d la so le \n",num);
printf("\n");
}
1. Tạo file function.c // hàm phân biệt chẵn lẻ
Code:
int odd_even(int x)
{
if(x % 2 == 0)
return 1;
else
return 0;
}
2. Tạo file header.h // khai báo nguyên hàm nguyên mẫu
Code:
int odd_even(int x);
Tạo file Makefile // nội dung make
- Code không sử dụng biến:
main: main.o function.o
gcc main.o function.o -o main
main.o: main.c
gcc -c main.c
function.o: function.c header.h
gcc -c function.c
clearn:
rm *.o
Môn học: Lập trình hệ thống
Phần: Hệ điều hành Linux Trang 57
- Code có sử dụng biến:
USER_DIR=..
WORK_DIR=$(USER_DIR)/Desktop/makefile
CC=gcc
OBJECT=main.o function.o
MAIN_FILE=main
MAIN_FILE: $(OBJECT)
$(CC) $(OBJECT) -o $(MAIN_FILE)
$(WORK_DIR)/main.o: $(WORK_DIR)/main.c
CC -c $(WORK_DIR)/main.c
$(WORK_DIR)/function.o: $(WORK_DIR)/function.c
CC -c $(WORK_DIR)/function.c
clearn:
rm *.o
3. Từ Terminal với đường dẫn trong thư mục các file vừa tạo, gõ lệnh :
a. make // thực thi Makefile
b. ./main // chạy chương trình
c. make clean // xóa file .o ( không cần thiết)