Các lệnh Linux cơ bản (phần 3 – I/O Redirection)

Hôm nay lại là một bài viết nữa trong chuỗi chủ đề về các câu lệnh cơ bản trong Linux. Ở bài viết trước chúng ta đã cùng nhau tìm hiểu xem cách đọc man page của một câu lệnh để hiểu rõ hơn về câu lệnh đó. Ở bài viết này, mình sẽ giới thiệu cho các bạn một chuỗi các lệnh quan trọng khi làm việc với Input và Output. Sau bài này, các bạn hãy sử dụng các lệnh của bài trước để tìm hiểu sâu hơn về các lệnh mình đã giới thiệu nhé. Chúng ta cùng bắt đầu thôi.

Trước khi đi vào các lệnh chúng ta đều biết rằng:

  • chương trình đều sinh ra output. Output thì thường bao gồm 2 phần, output mong muốn của một chương trình, và các error messages.
  • Một chương trình chạy trên Linux sẽ gửi đầu ra vào một file đặc biệt là stdout (standard output) và error messages đến stderr (standard error). Hai file này được link đến màn hình và không được save lại trong file.
  • Thêm vào đó, các chương trình thường lấy đầu vào từ stdin (standard input) được attach với bàn phím.
  • I/O rediretion cho phép chúng ta thay đổi nơi output ra và nơi input đến.

Hãy giữ những khái niệm đó trong đầu và giờ chúng ta cùng tìm hiểu các lệnh.

Redirect standard output

Để redirect output của một lệnh hay một chương trình ra một file khác stdout, chúng ta sử dụng ký hiệu > [file_name]. Ví dụ, để redirect output của lệnh ls ra một file tên foo.txt:

➜  /tmp ls > foo.txt
➜  /tmp
➜  /tmp ls -l foo.txt 
-rw-rw-r-- 1 hunguyen hunguyen 405 Th05 19 11:36 foo.txt

Chúng ta sẽ thấy lệnh trên không in kết quả vì kết quả đã được redirect đến foo.txt rồi.

Vậy nếu ta thực hiện lệnh trên với một directory không tồn tại thì sao.

➜  /tmp ls /foo/bar > foo.txt
ls: cannot access '/foo/bar': No such file or directory
➜  /tmp ls -l foo.txt 
-rw-rw-r-- 1 hunguyen hunguyen 0 Th05 19 11:40 foo.txt

Chúng ta vẫn thấy kết quả lỗi in ra màn hình vì chúng ta mới chỉ redirect output thôi còn error thì vẫn được lưu trong stderr, file foo.txt thì không có gì vì output không trả ra gì cả.

Chúng ta có thể thấy là file foo.txt bị overwrite vì chúng ta đang sử dụng >, để append vào file output chúng ta phải sử dụng >>. Ví dụ:

➜  /tmp ls -l foo.txt 
-rw-rw-r-- 1 hunguyen hunguyen 20769 Th05 19 11:44 foo.txt
➜  /tmp ls /home/hunguyen >> foo.txt 
➜  /tmp ls -l foo.txt               
-rw-rw-r-- 1 hunguyen hunguyen 21006 Th05 19 11:45 foo.txt

Redirect standard error

Một chương trình có thể sinh ra output trên rất nhiều file streams.

Chúng ta đã biết 3 loại file stream là stdin, stdout, stderr.

Shell tham chiếu chúng tương ứng với 3 file descriptor là 0, 1, 2.

Shell cho phép chúng ta định nghĩa I/O redirecion bằng cách sử dụng file descriptor number.

Để redirect error chúng ta file sử dụng file descriptor tương ứng là 2:

➜  /tmp ls /foo/bar 2> foo-error.txt
➜  /tmp    
➜  /tmp ls -l foo-error.txt 
-rw-rw-r-- 1 hunguyen hunguyen 56 Th05 19 11:58 foo-error.txt

như vậy chúng ta đã không thấy output error trên màn hình nữa mà nó đã được update trong file foo-error.txt

Redirect output & error ra cùng một file

Chúng ta có thể sử dụng một trong các cách sau để redirect cả error và output ra cùng một file

ls -l /bin/usr > ls-output.txt 2>&1
ls -l /bin/usr &> ls-output.txt
ls -l /bin/usr &>> ls-output.txt

Cách đầu tiên là cách thực hiện trong shell ở các phiên bản cũ: redirect stdout ra một file sau đó redirect stderr ra stdout (lưu ý đúng thứ tự trên nếu không sẽ không chính xác).

Cách thứ hai là là cho các version đến hiện tại của shell, dòng 3 là redirect và append vào một file.

Loại bỏ những đầu ra không mong muốn

Đôi khi chúng ta có thể không muốn nhìn thấy output của chương trình ra màn hình lẫn ra file. Hệ thống cung cấp một cách để redirect những đầu ra này ra một file đặc biệt gọi là /dev/null. File này chấp nhận đầu vào và không làm gì với nó cả. Để loại bỏ những error message không mong muốn chúng ta có thể thực hiện lệnh sau:

ls -l /bin/usr 2> /dev/null

Redirect standard input

Trước hết chúng ta sẽ giới thiệu về lệnh cat. Lệnh cat dùng để nối các file và redirect chúng ra stdout:

cat [file...]

trong đó [file...] có thể là một hoặc nhiều file.

nếu chúng ta sử dụng cat mà không truyền vào tham số nào. Nó sẽ nhận nội dung chúng ta nhận vào bàn phím và in chúng ra màn hình, sau khi chúng ta nhấn ctrl+d.

➜  ~ cat 
this is a demo    
this is a demo
➜  ~

chúng ta cũng có thể redirect đầu ra của lệnh cat vào một file, làm cat giống như một dummy text editor

➜  /tmp cat > foo.txt
This is a demonstration
➜  /tmp cat foo.txt 
This is a demonstration

Sau đây là cách chúng ta có thể redirect stdin, chuyển input từ 1 file thay vì bàn phím:

➜  /tmp cat < foo.txt 
This is a demonstration

Nhìn ví dụ trên thì có vẻ hơi dummy nhưng đó chính là cách chúng ta hiểu về redirect input với operator <, mặc dù việc này không cải thiện việc dùng câu lệnh cat chút nào.

Pipelines

Pipeline là chức năng redirect standard output của một command đến standard input của một command khác bằng operator |.

Chúng ta có thể hiển thị content của một directory lớn trong less để có thể search, hiển thị phân trang:

$ ls -l /usr/bin | less

Filters

Chúng ta có thể sử dụng filter trong pipeline để biến đầu ra (output của một lệnh) thành kết quả mong muốn rồi đưa ra standard output.

Các filter phổ biến là: sort, uniq

Ví dụ, để nhìn thấy list uniq của một vài directory trong less:

$ ls /bin /usr/bin | sort | uniq | less

Hoặc chúng ta có thể sử dụng option -d của uniq để chỉ nhìn thấy list những dòng có từ một lần xuất hiện trở lên

wc – line, word, byte count

câu lệnh wc dùng để đếm dòng, từ, byte trong một file. Chúng ta có thể dùng nó để đếm số uniq file, directory trong một directory.

$ ls /bin /usr/bin | sort | uniq | wc -l
2728

grep

Có lẽ chúng ta đã quá quen với lệnh grep rồi, dùng để match tên file/directory nội dung file. Khi gặp một file có chứa pattern cần search nó sẽ in dòng đó ra standard output

grep pattern [file...]

Ví dụ

➜  /tmp ls /bin /usr/bin | sort | uniq | grep zip
bunzip2
bzip2
bzip2recover
funzip
gpg-zip
gunzip
gzip
mzip
preunzip
prezip
prezip-bin
unzip
unzipsfx
zip
zipcloak
zipdetails
zipgrep
zipinfo
zipnote
zipsplit

head/tail

Hai câu lệnh trên tương ứng để in ra phần đầu và phần cuối của file. Mặc định chúng sẽ in ra 10 dòng đầu hoặc cuối của một file. Chúng ta có thế sử dụng option -n [number of lines] để định nghĩa số dòng muốn in ra

➜  /tmp ls /bin /usr/bin | sort | uniq | head -n 4

[
2to3
2to3-2.7
➜  /tmp ls /bin /usr/bin | sort | uniq | tail -n 4 
zmore
znew
zsh
zsh5

tail có một option -f mà chắc ai cũng biết để output realtime content của một file.

tee

Lệnh cuối cùng mà chúng ta tìm hiểu trong bài này đó là tee đọc stdin và redirect nó ra một hoặc nhiều file khác nhau, chúng ta dùng nó để ghi lại một kết quả cụ thể trong một đoạn nhất định của pipelines, tưởng tượng nó là ống nước chữ T để chia nguồn nước vậy

Ví dụ:

➜  /tmp ls /usr/bin | tee ls.txt | grep zip
funzip
gpg-zip
mzip
preunzip
prezip
prezip-bin
unzip
unzipsfx
zip
zipcloak
zipdetails
zipgrep
zipinfo
zipnote
zipsplit
➜  /tmp head ls.txt 
[
2to3
2to3-2.7
2to3-3.5
411toppm
7z
7za
a11y-profile-manager-indicator
aa-enabled
aclocal

Như vậy trong bài hôm nay chúng ta đã tìm hiểu được cách để làm việc với input và output. Bài tiếp theo mình sẽ giới thiệu thêm một khái niệm trong shell gọi là Shell expansion và một số thủ thuật dùng bàn phím hiệu quả khi làm việc trên terminal. Các bạn hãy đón đọc nhé.

  • Linux

Leave a Reply

Your email address will not be published. Required fields are marked *