Các Lược Giảng Chuyên Sâu về Sử Dụng Văn Lệnh BASH trong Linux/Bài 1

Từ Thư viện Khoa học VLOS
Bước tới: chuyển hướng, tìm kiếm

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ự

Những lưu ý tổng quát

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ự

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 #

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

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

Đặc biệt dòng bi chú bắt đầu bởi  #![đường_dẫn_cho_trình_dịch] 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)

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)

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 :

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 ]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])

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;] }

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, ...}

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ã {... }

Để 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])

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

Đổi hướng xuất từ stdout sang tập tin >

Để 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 >>

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) <

Đổi hướng từ stdin sang đọc từ một tập tin

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

Đô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

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 <<

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  |

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ự &

Để 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

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ế"



Trở về mục lục

Đọc bài kế

Liên kết đến đây