linux basic stdout stdin stderr - It costs 4 mins to read

Khi chúng ta gõ lệnh vào terminal, chúng đều trả về một output. Ví dụ:

$ echo hello
hello

Standard output

Nếu bạn nghĩ lệnh echo hello dùng để xuất chữ hello ra màn hình terminal thì bạn chỉ đúng một phần thôi. Mỗi hệ điều hành dựa trên nền tàng Unix có một khái niệm là “a default place for output to go” - hay còn gọi lại Standard Output (hay stdout). Là một nơi để chứa những output dùng để hiển thị lên màn hình cho bạn được thấy.

Standard input

Standard input (hay stdin) là một nơi mặc định mà commands sẽ lắng nghe để nhận tham số input. Ví dụ, nếu bạn gõ cat mà không có tham số, nó sẽ lắng nghe input trong stdin và xuất ra những gì bạn đã gõ vào đó, cho đến khi gặp ký tự EOF (CTRL+D).

Bất kì lệnh nào trong Unix đều có stdout và stdin.

Để không trả về output nào, bạn có thể redirect output đó về một tập tin đặc biệt là > dev/null. dev/null sẽ nuốt chửng mọi thứ truyền vào cho nó và không làm gì cả.

Pipes

Pipes làm trung gian và kết nối standard output của một lệnh thành standard input của một lệnh khác. Ví dụ:

$echo "hello there"
hello there
$echo "hello there" | sed "s/hello/hi"
hi there

Ở đây, standard output “hello there” của lệnh echo đã trở thành đầu vào của lệnh sed và sed đã thay chữ hello bằng chữ hi và in kết quả vào stdout (rồi hiển thị lên màn hình).

$ echo "hello there" | sed "s/hello/hi/" | sed "s/there/robots/"
hi robots

Standard error

Standard Error (hay stderr) cũng giống như standard output và standard input, nó là nơi mặc định để các thông điệp lỗi đi đến. Để xem một số stderr output, bạn thử catting một file không tồn tại xem.

$cat does-not-exist
cat: does-not-exist: No such file or directory

stderr khá giống stdout nhưng nếu nó vô hiệu khi bạn muốn dùng stderr với Pipes

$ cat does-not-exist | sed 's/No such/ROBOT SMASH/'
cat: does-not-exist: No such file or directory

Bởi vì Pipes lấy stdout chứ không phải stderr. Vậy ngoài cách sử dụng Pipes, còn cách nào để redirect output.

Redirecting output

Mặc định, stdout và stderr đều được in lên màn hình terminal, đó là lý do vì sao mà chúng ta có thể thấy được chúng. Nhưng chúng ta có thể redirect output vào một file bằng cách sử dụng dấu >

$ echo hello
hello
$ echo hello > new-file
$ cat new-file
hello

Ở đây lệnh > new-file thực hiện 2 công việc cùng lúc:

Thay vì ghi đè, bạn có thể ghi nối (append) bằng cách dùng dấu >>

$ cat new-file
hello
$ echo hello again >> new-file
$ cat new-file
hello
hello again

File descriptors

File descriptors là một biến số nguyên dương tham chiếu đến một nguồn input/output cụ thể: 0 là stdin, 1 là stdout, 2 là stderr. Xem thêm tại đây. Sử dụng dấu >& để redirect input/output bằng File descriptors.

# Redirect stdout to stdout (FD 1)
$ echo "hello there" >&1
hello there
# Redirect stdout to stderr (FD 2)
$ echo "hello there" >&2
hello there

Ứng dụng của File Descriptors:

# Redirect to stdout, so it comes through the pipe
$ echo "no changes" >&1 | sed "s/no/some/"
some changes
# Redirect to stderr, so it does not come through
$ echo "no changes" >&2 | sed "s/no/some/"
no changes

Advanced file descriptors

Giả sử chúng ta muốn thêm Robot says vào nội dung của các file - file1, file2, file3 nhưng do file2 là stderr, nó không thể được nhận bởi lệnh sed nên chúng ta phải redirect stderr thành stdout bằng File descriptors, cụ thể cách làm như sau - chuyển 2 (stderr) về 1 (stdout) bằng 2>&1:

$ ./command file1 file2 file3 2>&1 | sed "s/std/Robot says: std/"
Robot says: stderr file2
Robot says: stdout file1
Robot says: stdout file3

Ứng dụng thực tế

Chuyển tất cả stdout và stderr vào một log-file.

$ ./command file1 file2 file3 > log-file 2>&1
$ cat log-file
stderr file2
stdout file1
stdout file3

Bạn cần chú ý về thứ tự của lệnh trên sẽ dẫn đến kết quả hoàn toàn khác, thứ tự đúng phải là

> log-file 2>&1

chứ không phải là

2>&1 > log-file

Vì lệnh này sẽ redirect stderr về stdout (vốn được in ra màn hình) và stdout được redirect đến log-file, nhưng stderr sẽ không đi theo vì stderr được chỉ đến stdout “cũ”.

# Redirect stdout, because it's plain `>`
$ ./command file1 file2 file3 > log-file
stderr file2
# Redirect stderr, because it's `2>`
$ ./command file1 file2 file3 2> log-file
stdout file1
stdout file3

Nguồn bài viết: https://robots.thoughtbot.com/input-output-redirection-in-the-shell.