Các lệnh trên Shell (P6)

Bài viết này mình giới thiệu về Expansion.

Mỗi thời điểm bạn gõ một lệnh và nhấn Enter, bash biểu diễn vài xử lý trên các ký tự của bạn trước khi trả về kết qủa. Tiến trình tạo điều này xảy ra gọi là expansion. Với expansion, bạn gõ một cái gì đó rồi được mở rộng thành một cái gì đó khác trước khi Shell xử lý.

Để minh họa, mình nói sơ qua về lệnh echo. echo là một lệnh dạng built-in trên Shell, biểu diễn một tác vụ đơn giản như in ra một đoạn text trên Terminal:

leaf@leaf-X455LA:~$ echo hello
hello
leaf@leaf-X455LA:~$

echo cũng có thể kết hợp với các wildcards để hiệu qủa hơn, ví dụ:

leaf@leaf-X455LA:~$ echo ~/MyData/*
/home/leaf/MyData/AllCode /home/leaf/MyData/Data /home/leaf/MyData/vidu_shell
leaf@leaf-X455LA:~$

Pathname Expansion

Như ví dụ ở trên, việc dùng các wildcards được gọi là expansion tên đường dẫn hay expansion pathname. Ví dụ, liệt kê danh sách tên các thư mục trong thư mục hiện hành bằng ls:

leaf@leaf-X455LA:~$ ls
Desktop    Downloads  examples.desktop  Music   opencv    Public  Templates
Documents  Dropbox    Matlab            MyData  Pictures  Qt      Videos
leaf@leaf-X455LA:~$

Hay in ra các thứ (file/folder) bắt đầu bằng “M” có trong thư mục hiện hành (Chú ý là chỉ trong thư mục hiện hành, nếu muốn in ra trong thư mục con của nó, bạn dùng lệnh cd tới thư mục con của nó):

leaf@leaf-X455LA:~$ echo M*
Matlab Music MyData
leaf@leaf-X455LA:~$

Hoặc in ra các thứ (file/folder) bắt đầu bằng các ký tự in hoa:

leaf@leaf-X455LA:~$ echo [[:upper:]]*
Desktop Documents Downloads Dropbox Matlab Music MyData Pictures Public Qt Templates Videos
leaf@leaf-X455LA:~$

Bạn có thể thử thêm với một số wildcards khác!

Tidle expansion (dấu “~”)

Bài viết về các lệnh điều hướng trên Shell, các bạn có thấy qua  các ví dụ của mình có dùng cd ~/Downloads hoặc cd ~/MyData,… thì giờ bạn sẽ hiểu rõ “~” là phím tắt của cái gì:

leaf@leaf-X455LA:~$ echo ~
/home/leaf

Như trên ví dụ, “~” tượng trưng cho thư mục /home/user trên Linux, trường hợp của mình là /home/leaf.

Arithmetic expansion (số học)

Bạn có thể in ra kết quả của một biểu thức số học bằng cách sử dụng echo kèm theo cú pháp: $((expression)), ví dụ:

leaf@leaf-X455LA:~$ echo $((2 + 2))
4

Một số ví dụ khác:

leaf@leaf-X455LA:~$ echo $((5**2))
25

Toán tử “**” trên Shell là phép lũy thừa, các bạn lưu ý.

leaf@leaf-X455LA:~$ echo $(($((3**2))*2))
18

leaf@leaf-X455LA:~$ echo $((6/2))
3

Bạn cũng có thể in ra kết qủa biểu thức kèm với đoạn text, ví dụ:

leaf@leaf-X455LA:~$ echo five plus three equal $((5+3))
five plus three equal 8
leaf@leaf-X455LA:~$

Brace Expansion (Dấu ngoặc nhọn)

Dấu ngoặc nhọn {…} trên Shell có nhiều công dụng trên Shell, ví dụ, bạn có thể in ra nhiều đoạn text với các thành phần chứa trong dấu ngoặc nhọn:

leaf@leaf-X455LA:~$ echo Get-{1,2,3}-out
Get-1-out Get-2-out Get-3-out
leaf@leaf-X455LA:~$

Hoặc bạn có thể dùng nó như một mảng, chứa các thành phần nào đó, ví dụ:

leaf@leaf-X455LA:~$ echo {1..9}
1 2 3 4 5 6 7 8 9
leaf@leaf-X455LA:~$ echo {A..Z}
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
leaf@leaf-X455LA:~$

Hoặc:

leaf@leaf-X455LA:~$ echo a{A{1,2},B{1,2}}b
aA1b aA2b aB1b aB2b
leaf@leaf-X455LA:~$

Parameter Expansion (Biến)

Trên Linux Shell có hai loại biến, đó là biến hệ thống và biến người dùng tự định nghĩa. Biến hệ thống do Linux tạo ra, được viết hoa ví dụ: USER, HOME,… còn biến tự định nghĩa do người dùng đặt ra, viết thường ví dụ name, age,…. Các bạn ghi nhớ chỗ này, sau này phần viết script chúng ta sẽ sử dụng biến khá nhiều.

Ví dụ, chúng ta in ra gía trị của biến với echo $ten_bien:

leaf@leaf-X455LA:~$ echo $USER
leaf
leaf@leaf-X455LA:~$ echo $HOME
/home/leaf
leaf@leaf-X455LA:~$

hoặc:

leaf@leaf-X455LA:~$ echo $((age = 22))
22

Lưu ý ở đây age là tên biến do mình đặt tên, USER, HOME là các biến hệ thống của Linux, để xem tên biến hệ thống của Linux, chúng ta dùng lệnh sau:

leaf@leaf-X455LA:~$ printenv | less

Nếu các bạn chưa hiểu ý nghĩa lệnh trên thì có thể xem lại pipelines trong phần chuyển hướng I/O của mình ở bài viết trước.

Command Subsitution (Lệnh thay thế)

Command substitution cho phép chúng ta xuất một lệnh như là một biểu thức, ví dụ:

leaf@leaf-X455LA:~$ echo $(ls)
Desktop Documents Downloads Dropbox examples.desktop Matlab Music MyData opencv Pictures Public Qt Templates Videos
leaf@leaf-X455LA:~$

hay như lệnh sau, nó nhận kết qủa của lệnh which cp như là tham số của ls rồi thực hiện:

leaf@leaf-X455LA:~$ ls -l $(which cp)
-rwxr-xr-x 1 root root 130304 Th03 11 02:10 /bin/cp
leaf@leaf-X455LA:~$

Có một cú pháp thay thế cho command substitution có trên các chương trình Shell và dĩ nhiên nó được hỗ trợ trên bash. Nó sử dụng dấu back-quotes (là dấu này ` `) để thay thế cho ký hiệu lấy gía trị (là cái này $(…)), ví dụ:

leaf@leaf-X455LA:~$ ls -l `which cp`
-rwxr-xr-x 1 root root 130304 Th03 11 02:10 /bin/cp

Quoting

Để tìm hiểu quoting là gì, bạn hãy lướt qua hai ví dụ sau:

leaf@leaf-X455LA:~$ echo Day la    vi du 1
Day la vi du 1

và:

leaf@leaf-X455LA:~$ $() echo Tong diem la $10.00
Tong diem la 0.00
leaf@leaf-X455LA:~$

Ở ví dụ thứ nhất, bạn muốn in ra đoạn chữ “Day la     vi du 1”, nhưng Shell chỉ in ra “Day la vi du 1”, bởi vì Shell đã tự bỏ qua nhiều ký tự khoảng trắng liên tiếp. Còn ở ví dụ thứ hai, Shell sẽ thay thế gía trị rỗng của biểu thức trước lệnh echo vào ký vị trí ký tự $ đằng sau.

Để khắc phục điều này, Shell cung cấp một kỹ thuật gọi là quoting, nếu bạn muốn khắc phục ví dụ thứ nhất, ta có thể làm như sau:

leaf@leaf-X455LA:~$ echo “Day la    vi du 1”
Day la    vi du 1
leaf@leaf-X455LA:~$

Double quotes (dấu nháy kép)

Nếu đặt một đoạn text vào trong dấu nháy kép, tất cả các ký tự đặc biệt được sử dụng bởi Shell mất hết tác dụng của nó và được sử dụng như các ký tự thông thường trong bảng chữ cái. Nhưng có ba trường hợp ngoại lệ là ký tự “$”, “\” (backslash)“` `” (back-quotes), nghĩa là khi sử dụng chúng trong double quotes đoạn text sẽ bị phân chia ra, các tidle, brace, pathname expansion sẽ bị dồn nén, nhưng các arithmetic, parameter expansion vẫn được thực hiện. Dùng double quotes chúng ta sẽ xử lý được trường hợp tên file hoặc folder có chứa khoảng trắng. Nếu trong các file của bạn có file nào có tên chứa khoảng trắng trong đó, khi sử dụng nó như một tham số của lệnh, Shell sẽ cố nhận lệnh đó với hai tham số, sẽ gây ra lỗi. Các bạn xem ví dụ sau:

leaf@leaf-X455LA:~$ ls -l van ban.txt
ls: cannot access van: No such file or directory
ls: cannot access ban.txt: No such file or directory
leaf@leaf-X455LA:~$

khi sử dụng double quotes:

leaf@leaf-X455LA:~$ ls -l “van ban.txt”
-rw-rw-r– 1 leaf leaf 10 Th04  5 14:45 van ban.txt
leaf@leaf-X455LA:~$

Ghi chú là các thao tác với parameter expansion, arithmetic expansion và command substitution vẫn thực hiện được trong double quotes, ví dụ:

leaf@leaf-X455LA:~$ echo “$USER $((2*3)) $(cal)”
leaf 6    Tháng tư 2016
CN T2 T3 T4 T5 T6 T7
1  2
3  4  5  6  7  8  9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30

leaf@leaf-X455LA:~$

Single quotes (dấu nháy đơn)

Nếu bạn muốn chặn tất cả các expansion, bạn sử dụng dấu nháy đơn, các bạn theo dõi ví dụ sau:

leaf@leaf-X455LA:~$ echo text ~/*.txt {a,b} $(echo leaf) $((2+3)) $USER
text /home/leaf/van ban.txt a b leaf 5 leaf
leaf@leaf-X455LA:~$ echo “text ~/*.text {a,b} $(echo leaf) $((2+3)) $USER”
text ~/*.text {a,b} leaf 5 leaf
leaf@leaf-X455LA:~$ echo ‘text ~/*.text {a,b} $(echo leaf) $((2+3)) $USER’
text ~/*.text {a,b} $(echo leaf) $((2+3)) $USER
leaf@leaf-X455LA:~$

Escaping characters (các ký tự thoát)

Nếu bạn muốn quote một ký tự đơn thì có thể dùng một dấu blackslash trước một ký tự. Các ký tự này được gọi là các escaping characters. Thường nó được dùng trong các double quotes để ngăn chặn các expansions. Ví dụ:

leaf@leaf-X455LA:~$ echo “So tien con lai cua nguoi dung $USER la: \$5.00”
So tien con lai cua nguoi dung leaf la: $5.00

Các escaping cũng được sử dụng khá phổ biến để loại bỏ các ý nghĩa đặc biệt của ký tự có trong tên file, thường là các ký tự “$”, “&”, “!”,” “. Ví dụ:

leaf@leaf-X455LA:~$ cat > ten\ xau.txt
day la mot ten xau
leaf@leaf-X455LA:~$ mkdir good_name
leaf@leaf-X455LA:~$ mv ten\ xau.txt good_name
leaf@leaf-X455LA:~$

Lưu ý, để in ra dấu “\” thì bạn sử dụng “\\” và nếu dùng backslash trong single quote thì nó sẽ mất đi ý nghĩa đặc biệt của mình và được sử dụng như một ký tự thông thường.

More backslash tricks

Nếu nhìn vào các man pages (Ở các bài trước), bạn sẽ chú ý sẽ có những tùy chọn được tạo thành bởi một dấu “-” (dash) và một ký tự, nhưng cũng có những tùy chọn được tạo bởi hai dấu dash (“–“) và một cái tên dài. Ví dụ:

ls -r

ls –reverse

Shell hỗ trợ cả hai bởi vì tùy thuộc vào người dùng, có người dùng trên Terminal thích kiểu ngắn gọn, còn có người thì viết script cần ý nghĩa rõ ràng.

Bây giờ, câu hỏi đặt ra là nếu một câu lệnh nào đó rất dài cho một dòng của Terminal, làm thế nào để xuống dòng mà Shell vẫn hiểu các dòng đó đều thuộc một câu lệnh? Vấn đề sẽ được giải quyết nếu bạn sử dụng backslash (\). Ví dụ:

leaf@leaf-X455LA:~$ echo “xin chao cac ban,\
>  day la vi du ve cong dung cua \
>  dau \\ tren shell”
xin chao cac ban, day la vi du ve cong dung cua  dau \ tren shell
leaf@leaf-X455LA:~$

Sử dụng backslash cho phép chúng ta nhúng ký tự newline vào một câu lệnh, sau đây là một số ký tự đặc biệt khi sử dụng với backslash:

Escaping characters

Tên

Có thể dùng

\n Ký tự xuống dòng Thêm các dòng trống vào đoạn text
\t Tab Chèn các ký tự tab ngang vào đoạn text
\a Alert Làm cho Terminal phát tiếng bip
\\ Dấu backslash Chèn vào một dấu backslash
\f Formfeed Gửi nó tới máy in bỏ ra trang

Ví dụ:

leaf@leaf-X455LA:~$ echo -e “Inserting several blank lines \n\n\n”
Inserting several blank lines

leaf@leaf-X455LA:~$ echo -e “Words\tseparated\tbyhorizonal\ttabs.”
Words    separated    byhorizonal    tabs.
leaf@leaf-X455LA:~$ echo -e “\aMy computer went \”beep\”.”
My computer went “beep”.

leaf@leaf-X455LA:~$ echo -e “DEL C:\\Win2k\\LEGACY_OS.exe”
DEL C:\Win2k\LEGACY_OS.exe
leaf@leaf-X455LA:~$

Dấu “\” được sử dụng khá phổ biến, nếu bạn đã học lập trình C/C++ hoặc vài ngôn ngữ khác, bạn cũng sẽ thấy công dụng tương tự. Bài viết này kết thúc ở đây, chào các bạn!

 

 

 

 

 

Advertisements

Author: phuoctv

My name is Phuoc. I'm interested in computer programming and sharing the knowledge. My email: phuoctv14@gmail.com

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s