2013-07-31 31 views
14

Tôi đang chơi với chuyển hướng shell i/o. Các lệnh Tôi đã thử (trong bash):Chuyển hướng vỏ i/o order

ls -al *.xyz 2>&1 1> files.lst 

ls -al *.xyz 1> files.lst 2>&1 

Không có *.xyz tập tin bất kỳ trong thư mục hiện hành.

Các lệnh này mang lại cho tôi các kết quả khác nhau. Lệnh đầu tiên hiển thị thông báo lỗi ls: *.xyz: No such file or directory trên màn hình. Nhưng cái thứ hai in thông báo lỗi này vào tập tin. Tại sao lệnh đầu tiên thất bại trong việc viết đầu ra lỗi cho tệp?

Trả lời

8

lỗi này:

ls: *.xyz: No such file or directory 

đang được viết trên stderr bởi ls nhị phân.

Tuy nhiên trong lệnh này:

ls -al *.xyz 2>&1 1> files.lst 

Bạn đang đầu tiên chuyển hướngstderr để stdout mà theo mặc định đi vào tty (terminal)

Và sau đó bạn đang chuyển hướng stdout vào một tập tin files.lst tuy nhiên, hãy nhớ rằng stderr không được chuyển hướng đến tệp vì bạn có stderr đến stdout chuyển hướng trướcstdout đến file chuyển hướng. stderr của bạn vẫn được ghi vào tty trong trường hợp này.

Tuy nhiên trong trường hợp thứ 2 bạn thay đổi thứ tự của chuyển hướng (đầu tiên stdout-file và sau đó stderr để stdout) và một cách đúng đắn chuyển hướng stderr đến một file mà cũng đang được sử dụng bởi stdout.

+10

Giá trị mặc định không theo mặc định là tty. Nó đơn giản được thừa hưởng từ trình bao. Nếu shell là tương tác và chạy trên một tty, sau đó stdout và stderr mặc định cho tty đó. Nếu vỏ không chạy trên một tty, sau đó họ không. Tôi nhận ra điều này có vẻ giống như một nit, nhưng điều quan trọng là không làm xáo trộn stdout với một thiết bị đầu cuối, và mọi người mắc lỗi đó rất thường xuyên. –

+3

Có nghĩa là trong ngữ cảnh của một trình bao tương tác vì OP đang chạy lệnh này trong một trình bao tương tác. – anubhava

2

Vì đơn đặt hàng không quan trọng. Trong trường hợp đầu tiên, trước tiên bạn chuyển hướng stderr (2) tới stdout (1). Sau đó, bạn chuyển hướng (1) vào một tệp. Nhưng stderr (2) vẫn được trỏ tới stdout của shell đang chạy lệnh. Việc trỏ (1) vào một tệp trong trường hợp này không thay đổi thiết bị đầu ra (2) được hướng vào, vì vậy nó vẫn đi đến thiết bị đầu cuối.

Trong trường hợp thứ hai, bạn chuyển hướng stdout (1) vào tệp. Sau đó, bạn trỏ stderr (2) đến cùng một vị trí 1 được chỉ, đó là tệp, do đó, thông báo lỗi đi vào tệp.

+3

Chủ yếu là chính xác, nhưng tôi đặt câu hỏi từ ngữ của câu 4 "Nhưng stderr vẫn được trỏ tới stdout" Sau khi fd 1 được chuyển hướng đến tệp, fd 2 vẫn được gắn với tệp (tệp tty là một tệp) liên kết với, nhưng không phải là stdout của lệnh. Có lẽ thay đổi câu đó để đọc 'stderr vẫn được trỏ tới stdout của shell đang chạy lệnh'. Quan trọng hơn, đừng xúi giục stdout với một thiết bị đầu cuối. Nó thường là một thiết bị đầu cuối, nhưng (có lẽ thường xuyên hơn) không. –

+0

@WilliamPursell Đồng ý, tôi đã thực hiện chỉnh sửa của bạn. Nó có lẽ là hợp lý trong trường hợp cụ thể này, nhưng không phải là một câu trả lời chung chung tốt. – user1676075

22

Bash manual có ví dụ rõ ràng (tương tự như của bạn) để cho biết rằng đơn đặt hàng quan trọng và cũng giải thích sự khác biệt. Đây là phần liên quan được trích dẫn (nhấn mạnh mỏ):

Note that the order of redirections is significant. For example, the command

ls >dirlist 2>&1

directs both standard output (file descriptor 1) and standard error (file descriptor 2) to the file dirlist, while the command

ls 2>&1 >dirlist

directs only the standard output to file dirlist, because the standard error was made a copy of the standard output before the standard output was redirected to dirlist.

This post giải thích từ quan điểm POSIX.

Xung đột xảy ra do sự khác biệt chính. > chuyển hướng không bằng cách thực hiện toán hạng bên trái (stderr) trỏ đến toán hạng bên phải (stdout) nhưng bằng cách sao chép toán hạng bên phải và gán nó sang bên trái.Khái niệm, phân công bằng bản sao chứ không phải bằng tham chiếu.

Vì vậy, đọc từ trái sang phải đó là cách này được giải thích bởi Bash: ls > dirlist 2>&1 phương tiện chuyển hướng stdout đến tập tin dirlist, tiếp theo là chuyển hướng của stderr để bất cứ điều gì stdout hiện đang trỏ đến (mà đã là file). OTOH ls 2>&1 > dirlist sẽ chuyển hướng stderr đến bất cứ điều gì stdout hiện trỏ đến (màn hình/thiết bị đầu cuối) và sau đó chuyển hướng stdout đến dirlist.

12

Chuyển hướng là:

  • chế biến từ trái sang phải.
  • giải thích lặp đi lặp lại:
    • một trước chuyển hướng có thể ảnh hưởng đến một sau một:
      • nếu một chuyển hướng trước đó đã chuyển hướng một dòng nhất định (xác định bởi một số mô tả tập tin, chẳng hạn như 1 cho stdout (mặc định) và 2 cho stderr), các chuyển hướng sau nhắm mục tiêu luồng đó đề cập đến phiên bản đã được chuyển hướng.
    • nhưng không phải ngược lại - một chuyển hướng sau không có tác dụng hồi tố trên là mục tiêu của một chuyển hướng trước đó:
      • ví dụ, nếu bạn chỉ định mô tả tập tin 1 làm mục tiêu trong một chuyển hướng trước đó, những gì 1 có nghĩa là tại thời điểm đó bị khóa, ngay cả khi 1 được chuyển hướng sau đó.
  • Lưu ý, tuy nhiên, đầu ra mà không thực sự được gửi đến tất cả chuyển hướng được đưa ra, và rằng bất kỳ tập tin đầu ra chuyển hướng mục tiêu được tạo ra hoặc cắt ngắn trước thực hiện lệnh bắt đầu (đây là lý do tại sao bạn không thể đọc từ và chuyển hướng đầu ra đến cùng một tệp với một lệnh duy nhất).

Áp dụng cho ví dụ từ câu hỏi:

  • >file 2>&1:

    • >fileđầu tiên chuyển hướng stdout (file descriptor 1, ngụ ý bởi không tiền tố > với một số mô tả tập tin) để xuất tệp file
    • 2>&1rồi chuyển hướng stderr (2) đến đã được chuyển hướng stdout (1).
    • Hiệu ứng thực là cả hai dòng gốc sẽ kết thúc bằng file.
  • 2>&1 >file:

    • 2>&1 ← liên kết đầu tiên thiết bị lỗi chuẩn đến lúc bấy giờ gốc stdout; vì mô tả tập tin 2 không tham gia chuyển tiếp thêm nữa, đầu ra stderr do đó sẽ được chuyển thành bất kỳ giá trị nào được định nghĩa là tại thời điểm đó - tức là gốc xuất xứ.
      • Về mặt kỹ thuật, mô tả tập tin stdout ban đầu là nhân đôi, và trùng lặp là gì stderr sau đó đề cập đến, điều này giải thích tại sao nó không bị ảnh hưởng bởi một chuyển hướng sau của thiết bị xuất chuẩn.
    • >file sau đó chuyển hướng giá trị gốc thành file - nhưng điều đó không còn ảnh hưởng đến việc chuyển hướng stderr đã bị khóa.
    • Hiệu ứng thực là chỉ có đầu ra được gửi trực tiếp đến đầu ra được ghi lại trong file, trong khi đầu ra được gửi tới đầu ra được xuất ra (stdout gốc, chưa được xác định).