Các Lược Giảng Chuyên Sâu về Sử Dụng Văn Lệnh BASH trong Linux/Bài 1
Loạt bài "Các Lược Giảng Chuyên Sâu về Sử Dụng Văn Lệnh BASH trong Linux" của tác giả Làng Đậu giữ bản quyền 2006. Người đọc chỉ được sử dụng cho mụch đích học tập hay giảng dạy cho cá nhân. Cấm mọi hình thức sao chép, đăng lại, hay in lại nhằm mụch đích mua bán hay trục lợi mà không có sự cho phép chính thức của tác giả. Mọi thông tin về việc phổ biến rộng rãi có tính quảng bá tài liệu này cho mụch đích giáo dục hay phê bình, đề nghị về nội dung bài giảng xin liên lạc về vo_quang_nhan@yahoo.com
Bài 1: Kí tự quy ước và các lệnh dạng kí tự
Mục lục
- 1 Những lưu ý tổng quát
-
2
Kí
tự
quy
ước
và
lệnh
dạng
kí
tự
- 2.1 Dòng bị chú với dấu #
- 2.2 Dấu phân cách ; thay thế cho kí tự xuống hàng (cariage return)
- 2.3 Lệnh trống :
- 2.4 Nhóm lệnh (dùng trình bao con) ([KHỐI_LỆNH])
- 2.5 Nhóm lệnh { [KHỐI_LỆNH;] }
- 2.6 Ngoặc mở rộng lệnh {THAM_SỐ1,THAM_SỐ2,THAM_SỐ3, ...}
- 2.7 Ngoặc khối mã {... }
- 2.8 Thực thi các mệnh lệnh và gán kết quả cho một biến hay một biểu thức bằng `[KHỐI_LỆNH]` hay bằng $([KHỐI_LỆNH])
-
3
Các
kí
tự
đổi
hướng
xuất
nhập
- 3.1 Đổi hướng xuất từ stdout sang tập tin >
- 3.2 Đổi hướng xuất từ stdout chép nối vào tập tin >>
- 3.3 Đổi hướng nhập stdin để nhập từ tập tin (hay dòng mã trực tiếp) <
- 3.4 Đổi hướng nhập stdin để nhập từ nhiều dòng mã trực tiếp hay tập tin <<
- 3.5 Dùng ống truyền dẫn (pipe) đổi hướng từ stdout sang stdin |
- 4 Thi hành lệnh trong nền bằng kí tự &
- 5 Chú thích
Những lưu ý tổng quát[sửa]
Các
văn
lệnh
đều
là
các
tập
tin
văn
bản
(text)
thông
thường
và
do
đó
chỉ
cần
thoả
mãn
các
luật
chung
của
Linux/UNIX
về
tên
và
định
dạng
của
tập
tin
văn
bản
là
đủ.
Mặc
dù
vậy,
để
có
thể
thi
hành
được
trọn
vẹn,
thì
một
tập
tin
văn
bản
phải
có
thuộc
tính
khả
thi
(executable)
và
dĩ
nhiên
nó
phải
không
có
lỗi
viết
mã.
Hãy
dùng
lệnh
chmod
+x [TÊN_VĂN_LỆNH]
để
chỉ
thị
giá
trị
khả
thi
cho
chương
trình
mà
bạn
viết
thử.
Bạn
có
thể
mượn
bất
kì
một
chưong
trình
soạn
thảo
văn
bản
đơn
giản
nào
để
viết
mã
như
là
vi
(vim),
KWrite,
Late
hay
ngay
cả
Word
Perfect
để
tạo
một
văn
lệnh
nhưng
hãy
nhớ
lưu
giữ
nó
đưới
dạng
văn
bản
thông
thường
(text)
hay
ASCII.
Bạn
cùng
có
thể
soạn
thử
văn
lệnh
bằng
wordpad
hay
các
chương
trình
soạn
thảo
của
Windows;
Tuy
nhiên,
khi
chạy
trên
Linux
nó
có
thể
cần
phải
chuyển
được
dịch
ra
dạng
văn
bản
Linux
(thí
dụ
dùng
lệnh:
dos2unix [TÊN_TẬP_TIN]
để
chuyển
đổi
định
dạng.
Tuy
nhiên,
tôi
không
khuyên
bạn
làm
cách
này
vì
lẽ
một
người
dùng
Linux
không
thể
nào
không
biết
cách
tạo
văn
bản
đơn
giản
bằng
công
cụ
Linux
mà
không
phải
mượn
bất
kì
thứ
gì
bên
ngoài
(Nếu
mượn
Windows
để
soạn
thảo
văn
lệnh
Linux
thì
giống
như
người
lấy
kìm
nhổ
đinh
để
...
nhổ
răng:
cái
kìm
phải
bị
"mài"
dũa
lại
nếu
không
bạn
sẽ
làm
hại
"cái
gốc
con
người") 1 2
Một
khi
đã
có
script
thì
bạn
có
thể
thi
hành
(gọi)
script
đó
bằng
dòng
lệnh
bash [TÊN_VĂN_LỆNH]
hay
chỉ
cần
nhập
[TÊN_VĂN_LỆNH]
để
thực
thi
các
mệnh
lệnh
trong
tập
tin.
Khi
viết
script
lần
đầu
tiên,
bạn
nên
tìm
hiểu
cách
dùng
của
một
số
lệnh
hệ
thống
quan
trọng
như
là
ls,
cat,
cp,
mkdir,
rm,
rmdir,
chmod,
...
Bạn
có
thể
tìm
thấy
các
lệnh
này
trong
phần
phụ
luc
cuối
bài.
Bạn
phải
có
một
đầu
cuối
màn
hình
(console
screen)
để
viết
và
thử
nghiệm
các
văn
lệnh.
Trong
da
số
các
trường
hợp,
ban
có
thể
dùng
một
đầu
cuối
X
(X
terminal)
-
bằng
cách
gõ
lệnh
xterm
hay
bằng
cách
nhấn
vào
trình
đơn
(menu)
gọi
màn
hình
Terminal
Emulation).
Tuy
nhiên,
khi
chạy
các
script
trong
X
Window,
thì
nhiều
thông
báo
từ
lệnh
mà
bạn
dùng
trong
script
có
thể
bị
cắt
bỏ
bởi
các
phần
mềm
đó
và
bạn
sẽ
có
ít
dịp
để
tìm
hiểu
sai
sót
(nếu
có)
hơn.
Một
cách
tốt
là
hãy
nhấn
tổ
hợp
phím
<ctrl>+<alt>+<F1>
để
đăng
nhập
vào
một
đầu
cuối
riêng
biệt.
Nếu bạn là người dùng "root" thì khi dùng dưới dạng này bạn sẽ toàn quyền chạy tất cả các lệnh hệ thống không bị một giới hạn nào. Tuy nhiên, đây là con dao hai lưỡi vì khi bạn có 1 thao tác sai lầm thì lập tức sẽ ảnh hưởng tới máy.
Lưu ý: Khi thực tập trên máy, hãy thật sự cẩn thận với các câu lệnh mà bạn dùng trong văn lệnh của mình. Nhất là các câu lệnh có tính chất phá hủy như lệnh xoá tập tinh, xóa người dùng, ... hay các lệnh có tính thay đổi đặc tính quản lý của hệ thống.
Quy ước chung dùng trong các bài giảng: Để tiện trình bày thông tin cho thật chính xác các quy ước sau đây sẽ được sử dụng. Lưu ý rằng, các điều này chỉ là quy ước riêng của loạt bài giảng.
Do kiến trúc của Linu/UNIX quy định nên các thư mục hay các thiết thiết bị khác đều được xem là một tập tin. Và tên đầy đủ của của một tập tin sẽ bao gồm đường dẫn (path) và tên của chính tập tin đó.
Tên đầy đủ của thư mục mà nó chứa tập tin được gọi là đường dẫn của tập tin đó.
Nếu
không
có
lưu
ý
thêm
thì
các
cụm
từ
[TÊN_TẬP_TIN]
hay
[TÊN_VĂN_LỆNH]
được
hiểu
là
tên
đủ
của
tập
tin
bao
gồm
đường
dẫn
(path)
và
tên
riêng
của
tập
tin
hay
văn
lệnh
đó.
Chữ tên riêng (hay đôi khi một chữ "tên" nếu không bị nhầm lẫn) có nghiã là tên của tập tin mà không có đường dẫn đi kèm.
Thí
dụ:
tên
riêng
của
một
thư
mục
trong
dạng
tên
đầy
đủ
/usr/local/share/man
sẽ
là
man
.
Tương
tự,
tên
riêng
của
một
tập
tin
mà
có
dạng
đầy
đủ
là
/etc/init.d/crond
/
sẽ
là
/crond
Kí tự quy ước và lệnh dạng kí tự[sửa]
Trong
BASH,
các
kí
tự
đặc
biệt
như
là
~,`,@,#.$.%,&,*,?,<,>,;,",...
đều
có
thể
mang
các
ý
nghiã
quy
ước
riêng.
Một
số
lớn
trong
chúng
thực
sự
là
các
mệnh
lệnh
đặc
trưng.
Sau
đây
là
một
số
kí
tự
và
ý
nghĩa
quy
ước
cần
biết
khi
viết
mã.
Số
khác
được
dùng
trong
các
phép
toán
hay
các
mệnh
lệnh
mở
rộng
đặc
biệt
sẽ
được
trình
bày
ở
các
bài
giảng
sau
Dòng
bị
chú
với
dấu
#
[sửa]
Tương tự như các ngôn ngữ khác, trong BASH người ta có thể viết các dòng thông tin mà trình dịch sẽ không có tác động trực tiếp và được dùng làm các dòng bị chú.
Dòng bị chú thông thường[sửa]
Trong
BASH,
để
tạo
một
dòng
bị
chú
chỉ
cần
đặt
ở
đầu
dòng
dấu
#.
Khác
với
C++,
người
ta
không
thể
viết
một
bị
chú
với
nhiều
dòng
liên
tục
(bằng
cách
sử
dụng
các
dấu
kiểu
/*
các
dòng
bị
chú
*/
Dòng bị chú thông báo trình dịch[sửa]
Đặc
biệt
dòng
bi
chú
bắt
đầu
bởi
#!
sẽ
được
dành
riêng
để
máy
biết
được
người
viết
mã
muốn
dùng
trình
thông
dịch
nào
để
chạy
mã
nguồn.
(Vì
BASH
là
ngôn
ngữ
tương
thích
được
với
nhiều
loại
khác
như
Korn
và
C-shell).
Dòng
thông
báo
này
nên
được
đặt
ở
dòng
mã
đầu
tiên
trong
tập
tin
Với
cách
này
người
ta
có
thể
chạy
một
tập
tin
văn
lệnh
bằng
nhiều
phiên
bản
hay
trình
dịch
khác
nhau
(chỉ
cần
thay
đổi
dòng
bị
chú
về
trình
dịch)[đường_dẫn_cho_trình_dịch]
Thí dụ:
#!/bin/bash # the line above request to run bash from /bin (not from anywhere else) #File name: test1 #This is comment line echo "Hello World!" #the only command to be run in this script is 'ls -al'
Hãy
soạn
và
lưu
nội
dung
trên
trong
tập
tin
tên
test1
ngay
tại
thư
mục
đang
hoạt
động,
rồi
dùng
lệnh
chmod
755
./test1
(hay
lệnh
chmod
+x
./test
)
để
làm
cho
nó
khả
thi
và
chạy
nó
bằng
lệnh
./test1
.
Từ
đây
về
sau,
các
bài
thí
dụ
sẽ
không
nhắc
lại
làm
thế
nào
để
cho
1
văn
lệnh
trở
thành
thi
hành
được.
Dấu
phân
cách
;
thay
thế
cho
kí
tự
xuống
hàng
(cariage
return)[sửa]
Trong
các
văn
lệnh
Linux,
mỗi
câu
lệnh
đơn
giản
có
thể
tự
nó
đứng
riêng
thành
một
dòng.
Để
có
thể
viết
một
dòng
với
nhiều
lệnh
có
thể
dùng
dấu
;
để
ngăn
cách
giữa
các
câu
lệnh
này.
Hơn
nữa,
trong
trường
hợp
một
câu
lệnh
bao
gồm
nhiều
dòng
thì
người
lập
trình
có
thể
viết
chung
thành
một
dòng
nhưng
phải
để
dấu
;
ngăn
cách
giữa
các
câu
lệnh
với
nhau
và
dùng
;
thay
cho
các
dấu
xuống
hàng
trong
một
câu
lệnh
có
nhiều
dòng.
Tuy
nhiên,
lưu
ý
rằng,
ở
giữa
hai
câu
lệnh
trong
một
tập
tin
mã
nguồn
BASH,
các
kí
tự
xuống
hàng
hay
kí
tự
"space",
"tab"
có
thể
được
đặt
nhiều
hơn
1
lần
và
do
đó,
giữa
hai
câu
lệnh,
bạn
hoàn
toàn
có
thể
đặt
vào
trong
đó
tùy
ý
nhiều
dấu
;
nhưng
điều
này
chỉ
gây
ra
bất
tiện
và
không
làm
thay
đổi
chức
năng
vận
hành
ngoại
trừ
việc
làm
cho
trình
dịch
đọc
và
thi
hành
mã
lâu
hơn.
Thí dụ: Hãy xem thi dụ sau đây gán cho biến a giá trị bằng 1, và sau đó kiểm nghiệm lại bằng câu lệnh if - else: Nếu đúng giá trị của a bằng 1 thì hiển thị dòng "succeed", ngược lại sẽ hiển thị dòng "failed". ($a là biểu thức chỉ nội dung giá trị mà biến a lưu giữ)
#!/bin/bash a=1 if [ $a = 1 ] then echo "succeed" else echo "failed" fi
# gán cho biến a giá trị 1 # nếu a có giá trị bằng 1 #thì #in ra dòng chữ "succeed" #nếu không thì #in ra dòng chữ "failed" #kết thúc câu lệnh "if"
Có
thể
dùng
cách
viết
khác
hơn
cách
thông
thường
như
trên,
người
viết
mã
có
thể
thay
vì
xuống
hàng
thì
thay
vào
đó
bằng
dấu
;
và
nội
dung
tập
tin
trở
thành:
#!/bin/bash a=1; if [ $a = 1 ]; then echo "succeed"; else echo "failed"; fi
Hay là:
#!/bin/bash a=1; if [ $a = 1 ] then echo "succeed" else echo "failed" fi
Dĩ nhiên, mỗi cách viết có ưu khuyết điểm riêng về sự trình bày nhưng nếu viết đúng chúng đều không ảnh hưởng gì đến chức năng hay thứ tự khi vận hành. Tuỳ theo thói quen và cách nhìn người viết mã có thể trình bày sao cho dể hiểu. Cùng một nội dung như trên có thể viết lại như sau:
#!/bin/bash a=1 if [ $a = 1 ]; then echo "succeed" else echo "failed" fi
Lưu ý: Không thể đặt dòng lệnh bắt đầu bằng dấu # làm hàng bị chú rồi ngăn nó với một câu lệnh thực thụ khác với câu bị chú bằng dấu ; Vì khi đó, toàn bộ dòng này sẽ được trình dịch hiểu là câu bị chú nên sẽ bỏ qua
Lệnh
trống
:
[sửa]
Trong
BASH,
dấu
:
được
quy
ước
là
một
lệnh
trống
tức
là
câu
lệnh
không
thi
hành
gì
hết
(tương
đương
với
dấu
;
trong
C/C++
hay
tương
đương
với
lệnh
nop;
trong
ASM).
Lệnh
này
luôn
luôn
có
gía
trị
luận
lý
trả
về
là
true.
Thí dụ:
#!/bin/bash let "n = 1" while : do echo "value of n is $n" let "n += 1" if [ $n -ge 3 ] then echo "program terminated." break fi done
Khối mã trên hoàn toàn tương đương với khối mã sau -- chỉ trình bày khác đi và thay : bởi (true):
#!/bin/bash let "n = 1" while (true); do echo "value of n is $n" let "n+=1" if [ $n -ge 3 ]; then echo "program terminated." break fi done
Cả hai khối trên khi thực thi đều sẽ cho kết quả :
value of n is 1 value of n is 2 value of n is 3 program terminated.
Trong thí dụ trên, sau khi biến n được cài đặt giá trị ban đầu là 1 thì vòng lặp sẽ được tiến hành. Trong mỗi chu kì, biến n được tăng giá trị 1 đơn vị; câu lệnh if sẽ kết thúc vòng lặp này một khi n > 3. Như vậy vòng lặp sẽ chạy vô hạn lần nếu thiếu câu lệnh break trong trường hợp này. "con kiến mày lèo cành đa leo phải vòng lặp leo ra leo vào"
Lưu
ý:
Trong
các
mệnh
đề
điều
kiện
và
cả
lệnh
gán
trực
tiếp
giá
trị
(chẳng
hạn
như
[
$n
-ge
3
]
và
a=1
)
thì
số
luợng
các
khoảng
trống
(space)
ở
giữa
các
toán
tử
và
phép
toán
phải
theo
đúng
cú
pháp
chặc
chẽ
nếu
không
trình
dịch
có
thể
báo
lỗi
hay
không
thực
đúng
như
mong
muốn
(trong
chẳng
hạn
ở
trên
thì
không
thể
viết
thành
[$n
-gt
3]
hay
a
=
1
.
Tuy
nhiên
lệnh
let
lại
cho
phép
đặt
các
toán
tử
và
phép
toán
ở
vị
trí
thỏi
mái
hơn
(tức
là
các
cách
viết
let
"n+=1"
,
hay
let
"
n
+=
1"
,
hay
let
"n
+=1"
đều
được
chấp
nhận
và
tương
đương
nhau
Nhóm
lệnh
(dùng
trình
bao
con)
([KHỐI_LỆNH]
)
[sửa]
[KHỐI_LỆNH]
)Trong mã nguồn, nếu có một nhóm lệnh nếu muốn được thực thi riêng lẽ độc lập bằng cách gọi lại trình bao để thực thi thì có thể nhóm chung lại trong cặp dấu ngoặc đơn. Vì trình bao của chương trình chính chịu trách nhiệm gọi lại chính mình để thực thi khối lệnh nằm trong dấu ngoặc nên ta gọi nó là "trình bao con" (sub shell).
Thí dụ:
#!/bin/bash touch myfile mkdir test (cd test; cp ../myfile .; cd ..)
Trong
thí
dụ
trên,
lệnh
touch
tạo
ra
một
tập
tin
không
có
nội
dung
là
myfile,
lệnh
mkdir
dùng
để
tạo
ra
một
thư
mục
là
test
và
(cd
test;
cp
../myfile
.;
cd
..)
sẽ
gọi
một
trình
bao
con
để
thực
thi
nhóm
lệnh
bao
gồm
di
chuyển
thư
mục
hiện
hoạt
(current
directory)
tới
thư
mục
test,
chép
tập
tin
myfile
từ
thư
mục
cha
vô
đó,
rồi
di
chuyển
hoạt
vị
trở
ra.
Nhóm
lệnh
{
[KHỐI_LỆNH;]
}
[sửa]
[KHỐI_LỆNH;]
}Giống như 2.2.4 nhưng ở đây, trình bao hiện tại sẽ chuyển sang thực thi nhóm lệnh này mà không tự gọi trình bao khác thực thi nó. Khi sử dụng cách này, lưu ý là giữa các câu lệnh phải hoặc là có dấu '; ' hoặc là dấu đầu dòng (xuống hàng mới) và phải có khoảng trống ở giữa dấu ngoặc nhọn với các câu lệnh. Cách dùng nhóm lệnh này thông dụng khi định nghiã hàm hay dùng trong các vòng lặp
Thi dụ: hai nhóm lệnh sau đây là tương đương
{ cd test; cp ../myfile . ; cd ..; }
hay:
{ cd test cp ../myfile . cd .. }
Ngoặc
mở
rộng
lệnh
{THAM_SỐ1,THAM_SỐ2,THAM_SỐ3,
...}
[sửa]
Trong trường hợp một lệnh BASH chấp nhận tham số để yêu cầu lệnh này thi hành lại vói các tham số khác thì có thể đặt các tham số này vào trong cặp dấu móc. Cách thức này còn được gọi là mở rộng dấu ngoặc (brace expansion) Thí dụ1: dòng lệnh sau đây cho phép người đọc yêu cầu hiển thị danh sách các tập tin có tên mở rộng (extension) .h và .cpp bên trong thư mục tên là test:
ls test/{*.cpp,*.h}
Lệnh trên tương đương với hai lệnh:
ls test/*.cpp; ls test/*.h
Thí dụ2: dòng lệnh sau đây sẽ cho phép chép (copy) hai tập tin là myfile.cpp và myfile.h vào trong thư mục test:
cp {myfile.cpp,myfile.h} test
Thí dụ3: Dòng lệnh này sẽ giúp tạo một lúc 3 thư mục con trong /home/myname là old ,new và report
mkdir /home/myname/{old,new,report}
Lưu ý:
- Không phải lệnh hệ thống nào cũng hổ trợ dấu ngoặc mở rộng (như lệnh find chẳng hạn)
- Để thử nghiệm mã nêu trên, trong cả hai thí dụ, thì thư mục test phải tồn tại và thêm vào đó, đối với thí dụ2, trong thư mục hiện tại (current directory) phải có sẵn hai tập tin myfile.cpp và myfile.h giữa các dấu phẩy ',' bên trong cặp dấu móc { } sẽ không được để một khoảng trống nào từ ngoại trừ tên của các tham số. Nếu viết sai cú pháp này thì trình dịch sẽ báo lỗi
Ngoặc
khối
mã
{...
}
[sửa]
Để
phân
lập
riêng
một
đọan
mã
người
lập
trình
có
thể
đặt
mã
đó
vào
giữa
cặp
dấu
móc
{
}
tạo
thành
một
khối
mã.
Tuy
nhiên,
trong
trường
hợp
dùng
khối
mã
thông
thường
thì
việc
viết
mã
trong
một
khối
chỉ
có
tính
hình
thức,
việc
dùng
cặp
dấu
móc
này
sẽ
có
ý
nghĩa
hoàn
toàn
khi
chúng
có
được
giá
trị
phân
lập
thực
thụ
(như
trong
trường
hợp
dùng
khối
mã
để
định
nghiã
hàm)
Thí dụ1: Hai đoạn sau đây là hoàn toàn tương đương
#!/bin/bash ls { cd test cp myfile yourfile cd .. }
#!/bin/bash ls cd test cp myfile yourfile cd ..
Thí dụ2: Thí dụ về hàm sau sẽ làm cho định nghiã khối mã trở nên có ý nghiã
#!/bin/bash function Welcome { echo "Welcome to $NAME" echo "today is `date`" }
NAME="myName" Welcome
Lưu ý: Trong nhiều ngôn ngữ lập trình (như C/C++ chẳng hạn) thì một biến mới được định định nghĩa bên trong khối lệnh chỉ có giá trị nội bộ và chúng sẽ mất hiệu lực (hay ngay cả bị trình dịch bắt lỗi) nếu dùng chúng bên ngoài khối lệnh. Điều này không đúng với BASH, nghiã là, một khi biến được định nghiã, thì nó sẽ có giá trị địa phương cho toàn bộ tập tin chứa định nghiã đó mà không bị giới hạn nội bên trong khối mã như trường hợp C/C++.
Thực
thi
các
mệnh
lệnh
và
gán
kết
quả
cho
một
biến
hay
một
biểu
thức
bằng
`[KHỐI_LỆNH]
`
hay
bằng
$([KHỐI_LỆNH]
)
[sửa]
[KHỐI_LỆNH]
`[KHỐI_LỆNH]
)
Dấu
huyền `
(backtick)
là
một
toán
tử
trong
Linux.
Nếu
đặt
một
dòng
lệnh
vào
giữa
hai
dấu
`
(xem
như
các
dấu
ngoặc
đặc
biệt)
sẽ
có
nghiã
là
yêu
cầu
trình
dịch
BASH
thực
thi
câu
lệnh
ở
trong
ngặc
này
và
trả
về
các
dữ
liệu
xuất
từ
ngỏ
ra
của
câu
lệnh
đó.
(Do
đó,
nếu
lệnh
này
không
được
gán
vào
giá
trị
của
một
biến
hay
biểu
thức
thì
hầu
như
bạn
sẽ
bị
báo
lỗi.
Thí dụ1: Đoạn mã sau đây sẽ đọc nội dung của tập tin account_file và lọc ra string "Dung Vo"
a=`cat account_file | grep "Dung Vo"` if [ "$a" = "" ]; then echo "There is no string 'Dung Vo' in the account_file" else echo "the sring :'Dung Vo' matched in account_file!" if
Thí dụ 2: Vòng lặp for sau đây sẽ nhận các dữ liệu từ ngỏ ra của lệnh ls và sau đó kiểm xem các tên đó là thư mục (directory), tập tin (file), hay thành phần đặc biệt.để hiển thị.
for file in `ls`; do if [ -d $file ]; then echo "$file if a directory" elif [ -f $file ]; then echo "$file is a regular file" else echo "$file is a specific file". fi done
Thí dụ3: Gán tất cả các thông tin trong tập tin list.txt và thêm vào đó dòng có chữ congratulation ở dòng đầu tiên để sử dụng vào nhiều nơi khác nhau mà không phải gọi lại tổ hợp mệnh lệnh này
WIN_LIST=$(echo "*** Congratulation ***"; cat list.txt) echo "$WIN_LIST"
Các kí tự đổi hướng xuất nhập[sửa]
Đổi
hướng
xuất
từ
stdout
sang
tập
tin
>
[sửa]
Để
có
thể
chuyển
hướng
các
thông
tin
từ
ngỏ
xuất
(output)
của
một
mệnh
lệnh
đưa
trực
tiếp
vào
tạo
thành
nội
dung
của
một
tập
tin
mới
hay
một
ngỏ
ra
chuẩn
(stderr,
stdout)
(3)
,
ta
có
thể
dùng
kí
tự
lớn
hơn
>
để
làm
việc
này.
(Xem
thêm
phụ
lục
các
thiết
bị
quan
trọng
trong
Linux)
Thí dụ1: Câu lệnh dùng để chuyển tất cả các hiển thị từ stdout của lệnh myscript tạo thành nội dung của tập tin my_file. việc làm này sẽ xóa toàn bộ tập tin my_file cùng tên (nếu có)
myscript > my_file
Thí dụ2: Tất cả các dữ liệu xuất ra từ hai ngỏ stdout và stderr đều được chuyển vào nội dung của tập tin my_file
myscript &>my_file
Lưu ý: Câu lệnh trên tương đương với câu lệnh:
myscript > my_file 2>&1
Thí dụ3: Chuyển nội dung thông tin xuất ra từ lệnh myscript vào thẳng stderr; với cách này thì tất cả thông tin xuất của myscript theo ngỏ stdout cũng sẽ trở thành thông tin xuất từ ngỏ stderr (nghĩa là một cách dùng để thông báo lỗi)
myscript >&2
Thí dụ4:
mycommand 1>/dev/null 2>/dev/null
Thí dụ5: Sử dụng kĩ thuật nhóm lệnh để xuất các thông báo chuẩn từ stdout của các câu lệnh vào làm thành một tập tin myfile:
(echo "The file list of the current directory today are:"; date; ls -A)> my_log_file
Đổi
hướng
xuất
từ
stdout
chép
nối
vào
tập
tin
>>
[sửa]
Tương
tự
như
khi
dùng
dấu
>
.
Điểm
khác
ở
đây
là
thay
vì
xoá
tập
tin
cùng
tên
nếu
có
thì
dấu
thực
thi
lệnh
chuyển
hướng
>>
chỉ
chép
thông
nối
tiếp
vào
phần
sau
của
tập
tin.
Thí dụ1: Câu lệnh sau đây sẽ có chức năng gần giống với thí dụ5 ở trên (2.3.1) và dĩ nhiên trong thí dụ 5; nếu tập tin my_log_file đã có từ trước thì nó sẽ bị thay thế bằng tập tin my_log_file mới trong khi thí dụ sau sẽ không xoá mà chép tiếp vào đó.
echo "The file list of the current directory today are:" >> my_log_file date >> my_log_file ls -A >> my_log_file
Xem như bài tập: Hãy điều chỉnh các dòng lệnh trong thí dụ trên sao cho nó trở thành hoàn toàn tương đương với thí dụ 5 trong 2.3.1
Đổi
hướng
nhập
stdin
để
nhập
từ
tập
tin
(hay
dòng
mã
trực
tiếp)
<
[sửa]
Đổi hướng từ stdin sang đọc từ một tập tin[sửa]
Thí
dụ1:
Dòng
lệnh
sau
dùng
để
hiển
thị
nội
dung
tập
tin
my_file.
Nó
tương
đương
với
lệnh
cat
my_file
cat < my_file
Thí
du2:
Dòng
lệnh
sau
đây
dùng
để
chép
toàn
bộ
dữ
liệu
trong
thiết
bị
/dev/sda
(thường
là
một
ổ
cứng)
sang
thành
một
tập
tin
(nhằm
mục
đích
lưu
trữ)
và
nó
tương
đương
với
lệnh
dd
if=/dev/sda
of=my_backup
dd </dev/sda >my_backup
Và
để
phục
hồi
lại
trong
truờng
hợp
ổ
cứng
tên
/dev/sda
bị
hư
có
thể
dùng
lệnh
dd
<my_backup
>/dev/sda
Lưu ý: Đây là cách lưu trữ "thô" chỉ nhằm giúp bạn hiểu thêm. Trong trường hợp lưu trữ thực tế; bạn có thể sẽ nén các dữ liệu đọc được để giảm choáng chỗ hay dùng các tiện ích chuyên dụng cho lư trữ khác và dở nén khi phục hồi.
Đổi hướng và đọc từng dòng từ một tập tin[sửa]
Đôi khi muốn truy cập từng dòng một của một tập tin có thể làm cách sau:
while read my_line do echo "$my_line" done <./my_file
Đổi hướng và đưa dữ liệu vào một chương trình tương tác[sửa]
Dùng cách này người ta có thể tự động hoá nhiều chương trình thông qua các script Thí dụ1: Giả sử bạn là thành viên của một máy chủ ftp địa chỉ xxx.yyy.zzz.ttt. Công việc của bạn hàng ngày là tải về để cập nhật từ máy này tất cả các tập tin mã nguồn có dạng *.c trong thư mục có tên My_login. Để khỏi lập lại các mệnh lệnh ftp ban có thể thiết lập tập tin my_ftp.txt có nội dung như sau:
My_login bin mget *.c a bye
Mỗi lần cần phải cập nhật hoá, thì bạn chỉ việc gõ lệnh:
ftp xxx.yyy.zzz.ttt < my_ftp.txt
Chương trình này sẽ yêu câu bạn gõ vào mật khẩu và sau đó tự nó sẽ thực thi các lệnh để tải về các tập tin *.c. Với cách chuyển hướng như vậy bạn sẽ tiết kiệm được nhiều thì giờ để gõ lệnh tay mỗi lần làm cùng 1 loại thao tác.
Lưu ý: Bạn hoàn toàn có thể dùng cách tương tự trên cho một số chương trình tườn gtác như là vi, fdisk, ..các chương trình này không yêu cầu phải gõ mật khẩu. Tuy nhiên, khi dùng fdisk nhớ cẩn thận không khéo bạn có thểxoá ổ cứng của chính bạn thì không ai cứu nổi đâu nhé.
Đổi
hướng
nhập
stdin
để
nhập
từ
nhiều
dòng
mã
trực
tiếp
hay
tập
tin
<<
[sửa]
Cách đổi hướng này còn gọi là hồ sơ HERE (tại chỗ). Nó cho phép người dùng đọc nhiều dòng dữ liệu cho đến khi gặp dòng nhãn (label) xác định trước.
Thí dụ1: Thay vì sử dụng cách để đăng nhập như trong mục 2.3.3.3, ở đây dùng cách cung ứng trực tiếp tên và mật mã qua hồ sơ HERE.
myName="<TÊN_NGƯỜI_DÙNG>" myPassword="<MẬT_KHẨU>" # "End_Of_Session is the LABEL ftp -n $IP <<End_Of_Session user "$myName" "$myPassword" #enable binary mode bin #upload 2 file myFilesname1 and myFilename2 put myFilename1 put myFilename2 #end ftp session bye # after this LABEL the HERE document is also end End_Of_Session
Thí dụ2: Sau đây là một cách dùng hồ sơ HERE để nhập dữ liệu tại chỗ thay vì phải nhập vào từ stdin vào một hàm. Trường hợp này sẽ tiện dùng nếu như hàm được gọi là một hàm thư viện dùng chung trong nhiều mụch đích nhưng lại có nhu cầu nhập dữ liệu trực tiếp từ đầu cuối giao diện (console)
GetData () { read name read class read school }
#input parameter values to the above function. GetData << MY_LABEL NgocUyen 12 Marie Curie MY_LABEL echo echo "your name:$name echo "your class: $class" echo "your school: $school" echo
Dùng
ống
truyền
dẫn
(pipe)
đổi
hướng
từ
stdout
sang
stdin
|
[sửa]
Dùng kĩ thuật pipe, người ta có thể đem tất cả (hay một phần) ngỏ ra của một lệnh biến thành ngỏ vô của lệnh mới.
Thí dụ1: Câu lệnh sau đây sẽ chuyển nội dung của myFile (đọc từ lệnh cat) sang ngỏ vào của lệnh grep (và lệnh grep trong nhiệm vụ sẽ chỉ hiển thị những dòng nào có string "John"
cat myFile | grep "John"
Thí dụ2: Câu klệnh sau cho phép tìm trong thư mục con "test" (của thư mục hiện tại) tất cả các tập tin có tiếp đầu ngữ là Myfile và có phần tên mở rộng (extension) và hiển thị khi xuất ra được đưa thẳng vào lệnh ls -l. Lệnh này sẽ cho phép hiển thị lại các tập tin tìm được từ lệnh find thành dạng đầy đủ.
find ./test/ -name "Myfile.*" | ls -l {}
Lưu ý: dùng kĩ thuật pipe bạn có thể chuyển tiếp ngỏ ra cuả một lệnh sang một lệnh khác nhiều lần.
Thí
dụ3:
Câu
lệnh
sau
sẽ
thực
thi
các
bước
tương
tự
như
trong
thí
dụ2;
nhưng
sau
đó,
tiếp
tục
lấy
ngỏ
ra
của
lệnh
ls
đưa
vào
ngỏ
vô
của
lệnh
grep
và
lệnh
grep
chỉ
cho
phép
hiển
thị
những
dòng
chữ
nào
bắt
đầu
kí
tự
"d"
(tức
là
chỉ
có
các
thư
mục
là
được
hiển
thị).
còn
lệnh
awk
cuối
cùng
chỉ
cho
hiển
thị
chữ
ở
vị
trí
thứ
9
(tức
là
vị
trí
chứa
tên
tập
tin).
Nói
gọn
lại,
dòng
lệnh
tổ
hợp
này
sẽ
tìm
trong
thư
mục
./test
các
thư
mục
con
có
tiên
bắt
đầu
bằng
"Myfile"
và
hiển
thị
chúng
ra
màn
hình
find ./test/ -name "Myfile*" | ls -l {} | grep "^d" | awk '{print $8}'
Ngoài ra, còn nhiều kí tự được dùng trong các phép toán, dùng trong việc mở rộng hệ vỏ, và dùng trong các chức năng chuyên biệt sẽ được trình bày lần luợc trong các bài giảng kế tiếp
Lưu
ý:
Ngoài
cách
đổi
hướng
thông
thường
như
trình
bày
trong
2.3;
người
ta
còn
sử
dụng
cách
cách
thức
đổi
hướng
khác
mượn
lệnh
exec
.
Phần
này
sẽ
đưọc
trình
bày
trong
phụ
lục
13
Thi
hành
lệnh
trong
nền
bằng
kí
tự
&
[sửa]
Để
thực
thi
một
mệnh
lệnh
một
cách
không
đồng
bộ
thì
có
thể
dùng
dấu
&
đặt
ở
vì
trí
sau
cùng
của
mệnh
lệnh
này.
Khi
đó,
mệnh
lệnh
sẽ
được
thực
thi
trong
nền
(back
gound)
và
nếu
đặt
lệnh
dạng
này
một
văn
lệnh
thì
trình
bao
sẽ
gọi
một
trình
bao
con
để
thực
thi
đông
thời
trả
về
giá
trị
0
và
tiếp
tục
thực
thi
các
lệnh
kế
tiếp
trong
trình
bao
(nếu
có).
Như
vậy
mệnh
lệnh
gọi
với
&
sẽ
tiếp
tục
được
thi
hành.
Nếu
các
lệnh
kiểm
soát
công
việc
(job
control)
không
được
dùng
thì
các
ngỏ
vào
chuẩn
của
các
mệnh
lệnh
chạy
trong
nền
dạng
này
sẽ
được
đổi
hướng
vào
thiết
bị
/dev/null.
Tiện
lợi
của
việc
thi
hành
trong
nền
là
khi
có
một
số
mệnh
lệnh
mà
người
gọi
không
cần
đợi
có
kết
quả
mà
có
thể
tiếp
tục
công
việc
cho
đến
sau
này.
Thí
dụ:
Hai
đoạn
mã
sau
đây
sẽ
được
thi
hành
khác
nhau.
Trong
khối
mã
thứ
nhất
BASH
sẽ
đợi
cho
đến
khi
lệnh
find
làm
xong
công
tác
mới
thực
thi
tiếp
lệnh
echo
.
Trong
khi
khối
mã
thứ
nhì
sẽ
chạy
lệnh
find
đó
trong
nền
và
tiếp
tục
thực
thi
dòng
kế
tiếp
là
lệnh
echo
ngay
lập
tức
#Using back ground process echo "searching and printing result into found.txt" find /etc -name "*log" > found.txt echo "continue" ls
#Not Using background process echo "searching and printing result into found.txt " find /etc -name "*log" > found.txt & echo "continue" ls
Chú thích[sửa]
1: : Sự khác biệt căn bản giữa một tập tin ASCII trong Windows và trong Linux là trong tập tin trong định dạng kiểu DOS/Windows các dấu xuống hàng (cariage return - 0D) thường đi kèm với dấu đầu dòng (newline - 0A) trong khi đó tập tin dạng này trong Linux chỉ có các dấu đầu dòng. Nhiệm vụ của lệnh dos2unix chỉ là để lấy những kí tự không tương thích và thay vào đó những gì cần thiết để làm cho tập tin trở nên tương thích với Linux
2: Cái răng, cái tóc là gốc con người (tục ngữ)
3: Trong BASH thì bộ mô tả tập tin (file descriptor) ngỏ vào chuẩn stdin còn được kí hiệu là 0< (hay 0 ), stdout được kí hiệu là 1> (hay 1), và stderr là 2> (hay 2) -- Xem thêm phụ lục trong các bài tới về các loại tập tin và thiết bị.
4: Root (dịch nghiã là gốc, hay tổ tiên) là người dùng có quyền truy cập mọi tập tin, có thể tiến hành mọi thao tác của hệ thống Linux. Root có thể hiểu là tài khoản của người quản trị. Khái niệm root này tương đương với khai niệm administrator (người quản trị) trong hệ thống Windows
5: Wildcard: Một đạng kí tự đặc biệt, tùy theo quy ước, có thể đại diện cho một hay dãy kí nào đó chưa xác định rõ ràng. Có nơi dịch là "kí tự thay thế"