Sao chép thực sự là phần quan trọng ở đây.
Chúng ta hãy xem nơi mô tả tập tin sẽ đi đến trước khi chuyển hướng. Đây thường là thiết bị đầu cuối hiện tại, ví dụ:
STDOUT ---> /dev/pts/1
STDERR ---> /dev/pts/1
Bây giờ, nếu chúng ta gọi ls -l
mà không chuyển hướng, đầu ra và thông báo lỗi đi đến thiết bị đầu cuối của tôi dưới /dev/pts/1
.
Nếu trước tiên chúng ta chuyển hướng STDOUT
tệp đến một tệp ( ls -l > dirlist
), nó sẽ trông như thế này:
STDOUT ---> /home/bon/dirlist
STDERR ---> /dev/pts/1
Khi chúng tôi sau đó chuyển hướng STDERR
đến một bản sao của STDOUT
's mô tả tập tin ( ls -l > dirlist 2>&1
), STDERR
đi đến một bản sao của /home/bon/dirlist
:
STDOUT ---> /home/bon/dirlist
STDERR ---> /home/bon/dirlist
Nếu trước tiên chúng tôi sẽ chuyển hướng STDERR
đến một bản sao STDOUT
mô tả tệp ( ls -l 2>&1
):
STDOUT ---> /dev/pts/1
STDERR ---> /dev/pts/1
và sau đó STDOUT
đến một tệp ( ls -l 2>&1 > dirlist
), chúng ta sẽ nhận được điều này:
STDOUT ---> /home/bon/dirlist
STDERR ---> /dev/pts/1
Đây, STDERR
vẫn đang đi đến nhà ga.
Bạn thấy đấy, thứ tự trong trang man là chính xác.
Kiểm tra chuyển hướng
Bây giờ, bạn có thể tự kiểm tra điều đó. Sử dụng ls -l /proc/$$/fd/
, bạn thấy nơi STDOUT
(với fd 1) và STDERR
(với fd 2), sẽ diễn ra cho quy trình hiện tại:
$ ls -l /proc/$$/fd/
total 0
lrwx------ 1 bon bon 64 Jul 24 18:19 0 -> /dev/pts/1
lrwx------ 1 bon bon 64 Jul 24 18:19 1 -> /dev/pts/1
lrwx------ 1 bon bon 64 Jul 24 07:41 2 -> /dev/pts/1
lrwx------ 1 bon bon 64 Jul 24 18:19 255 -> /dev/pts/1
Hãy tạo một tập lệnh shell nhỏ cho biết nơi mô tả tệp của bạn được trỏ. Bằng cách này, chúng ta luôn có được trạng thái khi gọi ls
, bao gồm mọi chuyển hướng từ vỏ gọi.
$ cat > lookfd.sh
#!/bin/sh
ls -l /proc/$$/fd/
^D
$ chmod +x lookfd.sh
(Với CtrlD, bạn gửi một tập tin cuối và vì vậy hãy dừngcat
lệnh đọc từ đó STDIN
.)
Bây giờ, gọi tập lệnh này với các kết hợp chuyển hướng khác nhau:
$ ./lookfd.sh
total 0
lrwx------ 1 bon bon 64 Jul 24 19:08 0 -> /dev/pts/1
lrwx------ 1 bon bon 64 Jul 24 19:08 1 -> /dev/pts/1
lrwx------ 1 bon bon 64 Jul 24 19:08 2 -> /dev/pts/1
lr-x------ 1 bon bon 64 Jul 24 19:08 255 -> /home/bon/lookfd.sh
$ ./lookfd.sh > foo.out
$ cat foo.out
total 0
lrwx------ 1 bon bon 64 Jul 24 19:10 0 -> /dev/pts/1
l-wx------ 1 bon bon 64 Jul 24 19:10 1 -> /home/bon/foo.out
lrwx------ 1 bon bon 64 Jul 24 19:10 2 -> /dev/pts/1
lr-x------ 1 bon bon 64 Jul 24 19:10 255 -> /home/bon/lookfd.sh
$ ./lookfd.sh 2>&1 > foo.out
$ cat foo.out
total 0
lrwx------ 1 bon bon 64 Jul 24 19:10 0 -> /dev/pts/1
l-wx------ 1 bon bon 64 Jul 24 19:10 1 -> /home/bon/foo.out
lrwx------ 1 bon bon 64 Jul 24 19:10 2 -> /dev/pts/1
lr-x------ 1 bon bon 64 Jul 24 19:10 255 -> /home/bon/lookfd.sh
$ ./lookfd.sh > foo.out 2>&1
$ cat foo.out
total 0
lrwx------ 1 bon bon 64 Jul 24 19:11 0 -> /dev/pts/1
l-wx------ 1 bon bon 64 Jul 24 19:11 1 -> /home/bon/foo.out
l-wx------ 1 bon bon 64 Jul 24 19:11 2 -> /home/bon/foo.out
lr-x------ 1 bon bon 64 Jul 24 19:11 255 -> /home/bon/lookfd.sh
Bạn có thể thấy rằng các mô tả tập tin 1 (cho STDOUT
) và 2 (cho STDERR
) khác nhau. Để giải trí, bạn cũng có thể chuyển hướng STDIN
và xem kết quả:
$ ./lookfd.sh < /dev/zero
total 0
lr-x------ 1 bon bon 64 Jul 24 19:18 0 -> /dev/zero
lrwx------ 1 bon bon 64 Jul 24 19:18 1 -> /dev/pts/1
lrwx------ 1 bon bon 64 Jul 24 19:18 2 -> /dev/pts/1
lr-x------ 1 bon bon 64 Jul 24 19:18 255 -> /home/bon/lookfd.sh
(Câu hỏi còn lại cho người đọc: Mô tả tệp 255 điểm ở đâu? ;-))