Làm thế nào để chuyển hướng đầu ra đến một tập tin và thiết bị xuất chuẩn


989

Trong bash, gọi foosẽ hiển thị bất kỳ đầu ra nào từ lệnh đó trên thiết bị xuất chuẩn.

Việc gọi foo > outputsẽ chuyển hướng bất kỳ đầu ra nào từ lệnh đó sang tệp được chỉ định (trong trường hợp này là 'đầu ra').

Có cách nào để chuyển hướng đầu ra sang một tệp để nó hiển thị trên thiết bị xuất chuẩn không?


3
Nếu ai đó vừa kết thúc ở đây đang tìm cách bắt đầu ra lỗi vào tệp, hãy xem - unix.stackexchange.com/questions/132511/ Lỗi
Murphy

2
Một lưu ý về thuật ngữ: khi bạn thực thi foo > output, dữ liệu được ghi vào thiết bị xuất chuẩn và thiết bị xuất chuẩn tệp có tên output. Đó là, ghi vào tệp đang ghi vào thiết bị xuất chuẩn. Bạn đang hỏi liệu có thể viết cả lên thiết bị xuất chuẩn và thiết bị đầu cuối không.
William Pursell

2
@WilliamPursell Tôi không chắc việc làm rõ của bạn sẽ cải thiện mọi thứ :-) Làm thế nào về điều này: OP đang hỏi liệu có thể hướng stdout của chương trình được gọi đến cả tệp và stdout của chương trình gọi hay không (sau này là thiết bị đầu ra mà chương trình được gọi sẽ kế thừa nếu không có gì đặc biệt được thực hiện, tức là thiết bị đầu cuối, nếu chương trình gọi là phiên bash tương tác). Và có lẽ họ cũng muốn điều khiển stderr của chương trình được gọi tương tự ("bất kỳ đầu ra nào từ lệnh đó" có thể được giải thích hợp lý có nghĩa là bao gồm cả stderr).
Don nở

Câu trả lời:


1379

Lệnh bạn muốn được đặt tên tee:

foo | tee output.file

Ví dụ: nếu bạn chỉ quan tâm đến thiết bị xuất chuẩn:

ls -a | tee output.file

Nếu bạn muốn bao gồm stderr, hãy làm:

program [arguments...] 2>&1 | tee outfile

2>&1chuyển hướng kênh 2 (lỗi chuẩn / lỗi tiêu chuẩn) thành kênh 1 (đầu ra tiêu chuẩn / đầu ra tiêu chuẩn), sao cho cả hai được viết là thiết bị xuất chuẩn. Nó cũng được chuyển đến tệp đầu ra đã cho theo teelệnh.

Hơn nữa, nếu bạn muốn chắp thêm vào tệp nhật ký, hãy sử dụng tee -anhư:

program [arguments...] 2>&1 | tee -a outfile

173
Nếu OP muốn "tất cả đầu ra" được chuyển hướng, bạn cũng cần lấy stderr: "ls -lR / 2> & 1 | tee output.file"
James Brady

45
@evanmcdonnal Câu trả lời không sai, nó chỉ có thể không đủ cụ thể hoặc hoàn thành tùy thuộc vào yêu cầu của bạn. Chắc chắn có những điều kiện mà bạn có thể không muốn stderr là một phần của đầu ra được lưu vào một tệp. Khi tôi trả lời điều này 5 năm trước, tôi cho rằng OP chỉ muốn thiết bị xuất chuẩn, vì ông đã đề cập đến thiết bị xuất chuẩn trong chủ đề của bài đăng.
Zoredache

3
Ah xin lỗi, tôi có thể có một chút bối rối. Khi tôi thử nó tôi chỉ không có đầu ra, có lẽ tất cả sẽ đi vào stderr.
evanmcdonnal

38
Sử dụng -ađối số teeđể nối thêm nội dung vào output.file, thay vì ghi đè nội dung đó:ls -lR / | tee -a output.file
kazy

16
Nếu bạn đang sử dụng $?sau đó, nó sẽ trả về mã trạng thái tee, đây có thể không phải là thứ bạn muốn. Thay vào đó, bạn có thể sử dụng ${PIPESTATUS[0]}.
LaGoutte ngày

501
$ program [arguments...] 2>&1 | tee outfile

2>&1đổ các dòng stderr và stdout. tee outfilelấy luồng nó nhận và ghi nó vào màn hình và vào tệp "outfile".

Đây có lẽ là điều mà hầu hết mọi người đang tìm kiếm. Tình huống có thể là một số chương trình hoặc kịch bản đang làm việc chăm chỉ trong một thời gian dài và tạo ra rất nhiều đầu ra. Người dùng muốn kiểm tra định kỳ để biết tiến trình, nhưng cũng muốn đầu ra được ghi vào một tệp.

Vấn đề (đặc biệt là khi trộn các luồng stdout và stderr) là có sự phụ thuộc vào các luồng được chương trình tuôn ra. Ví dụ, nếu tất cả các ghi vào thiết bị xuất chuẩn không bị xóa , nhưng tất cả các ghi vào stderr đều bị xóa , thì chúng sẽ kết thúc theo thứ tự thời gian trong tệp đầu ra và trên màn hình.

Cũng thật tệ nếu chương trình chỉ xuất 1 hoặc 2 dòng cứ sau vài phút để báo cáo tiến trình. Trong trường hợp như vậy, nếu chương trình không được chương trình tuôn ra, người dùng thậm chí sẽ không thấy bất kỳ đầu ra nào trên màn hình trong nhiều giờ, bởi vì không ai trong số đó sẽ bị đẩy qua đường ống trong nhiều giờ.

Cập nhật: Chương trình unbuffer, một phần của expectgói, sẽ giải quyết vấn đề đệm. Điều này sẽ khiến thiết bị xuất chuẩn và thiết bị xuất chuẩn ghi vào màn hình và tập tin ngay lập tức và giữ chúng đồng bộ khi được kết hợp và chuyển hướng đến tee. Ví dụ:

$ unbuffer program [arguments...] 2>&1 | tee outfile

7
Bất cứ ai cũng biết về một 'unbuffer' cho osx?
John Mee

7
Nếu bạn không thể sử dụng unbuffer, GNU coreutils bao gồm một công cụ có tên là stdbuff có thể được sử dụng để ngăn chặn bộ đệm đầu ra như vậy$ stdbuf -o 0 program [arguments...] 2>&1 | tee outfile
Peter

1
Nếu bạn đang sử dụng OS X, hầu hết các trường hợp sử dụng unbuffer sẽ dễ dàng hơn, mặc dù không phải nếu bạn muốn truyền tín hiệu cho lệnh bạn đang chạy. Nhận xét của tôi nhắm nhiều hơn vào người dùng sử dụng Linux, trong đó phần lớn được cài đặt theo mặc định. @Ethan, hãy xem câu trả lời này nếu bạn bối rối về cú pháp stdbuf: stackoverflow.com/a/25548995/942781
Peter

3
Lưu ý rằng pythoncó một tùy chọn tích hợp sẵn để giải -unén đầu ra.
fabian789

1
Nhân viên cứu hộ tuyệt đối để đào tạo các mô hình ML nơi tôi muốn đăng nhập mà không cần thêm mã nhưng cũng thấy đầu ra sau nhiều giờ / ngày để chạy, cảm ơn bạn!
rococo

126

Một cách khác phù hợp với tôi là,

<command> |& tee  <outputFile>

như thể hiện trong hướng dẫn sử dụng gnu bash

Thí dụ:

ls |& tee files.txt

Nếu '| &' được sử dụng, lỗi tiêu chuẩn của lệnh1 , ngoài đầu ra tiêu chuẩn của nó , được kết nối với đầu vào tiêu chuẩn của lệnh2 thông qua đường ống; nó là viết tắt cho 2> & 1 |. Điều này chuyển hướng ngầm định của lỗi tiêu chuẩn đến đầu ra tiêu chuẩn được thực hiện sau khi bất kỳ chuyển hướng nào được chỉ định bởi lệnh.

Để biết thêm thông tin, tham khảo chuyển hướng


10
Nếu bạn đang sử dụng $?sau đó, nó sẽ trả về mã trạng thái tee, đây có thể không phải là thứ bạn muốn. Thay vào đó, bạn có thể sử dụng ${PIPESTATUS[0]}.
LaGoutte ngày

1
Phương pháp này loại bỏ đầu ra giao diện điều khiển màu, bất kỳ ý tưởng?
shakram02

Thử: unbuffer ls -l --color = auto | tee files.txt
Luciano Andress Martini

17

Bạn chủ yếu có thể sử dụng giải pháp Zoredache , nhưng nếu bạn không muốn ghi đè lên tệp đầu ra, bạn nên viết tee với tùy chọn -a như sau:

ls -lR / | tee -a output.file

11

Một cái gì đó để thêm ...

Gói unbuffer có vấn đề hỗ trợ với một số gói theo fedora và redhat unix phát hành.

Gác lại những rắc rối

Sau đây làm việc cho tôi

bash myscript.sh 2>&1 | tee output.log

Cảm ơn ScDF & matthew đầu vào của bạn đã tiết kiệm cho tôi rất nhiều thời gian ..



3

Phần thưởng trả lời vì trường hợp sử dụng này đã đưa tôi đến đây:

Trong trường hợp bạn cần làm điều này như một số người dùng khác

echo "some output" | sudo -u some_user tee /some/path/some_file

Lưu ý rằng tiếng vang sẽ xảy ra khi bạn và việc ghi tệp sẽ xảy ra là "some_user", điều sẽ KHÔNG hoạt động nếu bạn chạy echo như "some_user" và chuyển hướng đầu ra với >> "some_file" vì chuyển hướng tệp sẽ xảy ra như bạn.

Gợi ý: tee cũng hỗ trợ nối thêm cờ -a, nếu bạn cần thay thế một dòng trong tệp như một người dùng khác, bạn có thể thực thi sed như người dùng mong muốn.


2

< command > |& tee filename # này sẽ tạo một tệp "tên tệp" với trạng thái lệnh dưới dạng nội dung, Nếu một tệp đã tồn tại, nó sẽ xóa nội dung tồn tại và ghi trạng thái lệnh.

< command > | tee >> filename # này sẽ nối trạng thái vào tệp nhưng nó không in trạng thái lệnh trên tiêu chuẩn (màn hình).

Tôi muốn in một cái gì đó bằng cách sử dụng "echo" trên màn hình và nối dữ liệu đó vào một tập tin

echo "hi there, Have to print this on screen and append to a file" 

1

Bạn có thể làm điều đó cho toàn bộ tập lệnh của mình bằng cách sử dụng một cái gì đó tương tự ở đầu tập lệnh của bạn:

#!/usr/bin/env bash

test x$1 = x$'\x00' && shift || { set -o pipefail ; ( exec 2>&1 ; $0 $'\x00' "$@" ) | tee mylogfile ; exit $? ; }

# do whaetever you want

Điều này chuyển hướng cả đầu ra stderr và stdout vào tệp được gọi mylogfile để mọi thứ đi vào thiết bị xuất chuẩn cùng một lúc .

Nó được sử dụng một số thủ thuật ngu ngốc:

  • sử dụng execmà không cần lệnh để thiết lập chuyển hướng,
  • sử dụng teeđể sao chép đầu ra,
  • khởi động lại tập lệnh với các chuyển hướng mong muốn,
  • sử dụng một tham số đầu tiên đặc biệt (một NULký tự đơn giản được chỉ định bởi $'string'ký hiệu bash đặc biệt) để chỉ định rằng tập lệnh được khởi động lại (không có tham số tương đương nào có thể được sử dụng bởi tác phẩm gốc của bạn),
  • cố gắng duy trì trạng thái thoát ban đầu khi khởi động lại tập lệnh bằng pipefailtùy chọn.

Xấu xí nhưng hữu ích cho tôi trong những tình huống nhất định.


-13

tee là hoàn hảo cho việc này, nhưng điều này cũng sẽ làm công việc

ls -lr / > output | cat output

10
Đó là một lỗi nếu đầu ra không tồn tại và nó không làm những gì bạn muốn nếu nó xảy ra, nói chung nó là vô nghĩa. Có lẽ bạn có nghĩa là ";" thay vì "|" ?
Robert Gamble

6
Ngay cả khi bạn đã sử dụng a ;, đầu ra sẽ bị chậm nhiều trong khi lệnh chậm.
Brad Koch
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.