Sao chép thiết bị xuất chuẩn và thiết bị xuất chuẩn vào tệp nhật ký và để chúng trên bàn điều khiển trong chính tập lệnh


11

Sử dụng bash, làm cách nào để sao chép stderr và stdout vào tệp nhật ký và cũng để chúng hiển thị trên bảng điều khiển?

Tôi muốn làm điều này trong chính kịch bản bằng cách sử dụng một exec.

Tôi đã thử với

exec &>> log.out

echo "This is stdout"
echo "This is stderr" >&2

Nhưng các bản in trên không có gì trên bảng điều khiển. Làm thế nào tôi có thể đạt được điều này trong bash?


Có một câu trả lời được đánh giá cao cho một câu hỏi tương tự trên StackOverflow trả lời câu hỏi này khá kỹ lưỡng. stackoverflow.com/a/692407/208257
Dan Burton

Câu trả lời:


10

Bạn đang tìm kiếm tee.

Xem man teeđể biết chi tiết.

Để kết hợp nó với exec, bạn phải sử dụng quá trình thay thế . (Xem man bashđể biết chi tiết.)

exec &> >(tee  log.out)
echo "This is stdout"
echo "This is stderr" >&2

Tôi đã nhìn vào nó. Làm exec 2>&1 | tee -a log.outchỉ in trên bàn điều khiển, không có gì trong file log. Có lẽ tôi không sử dụng đúng cú pháp?
adarshr

@adarshr Vui lòng kiểm tra lại mã của bạn. Tôi đã viết về teesự kết hợp với quá trình thay thế .
H.-Dirk Schmitt

1
Điều đó hợp nhất stdout và stderr mặc dù và có thể có cùng loại tác dụng phụ như được đề cập trong câu trả lời của tôi.
Stéphane Chazelas

@StephaneChazelas Hãy xem mã ví dụ trong câu hỏi - đó là ý định từ OP.
H.-Dirk Schmitt

Ý tôi là bằng cách hợp nhất là bây giờ các lỗi của tập lệnh đi đến thiết bị xuất chuẩn. Vì vậy, nếu ai đó làm the-script | wc -lví dụ, điều đó cũng sẽ đếm các dòng lỗi và bạn sẽ không thấy lỗi.
Stéphane Chazelas

5

Bạn có thể làm:

: > log # empty log file if necessary
{ { {

  ...the script

} 3>&- | tee -a log >&3 3>&-
exit "${PIPESTATUS[0]}"
} 2>&1 | tee -a log >&2 3>&-
} 3>&1
exit "${PIPESTATUS[0]}"

Bạn cũng có thể viết nó như sau:

: > log # empty log file if necessary
exec 2> >(tee -a log >&2) > >(tee -a log)

...the script

Nhưng vì bash không đợi các tiến trình đó bắt đầu >(...), điều đó có tác dụng khó chịu đôi khi xuất ra một cái gì đó cho thiết bị đầu cuối sau khi lệnh được trả về, có thể có các hiệu ứng thậm chí còn khó khăn hơn (như âm thầm loại bỏ đầu ra đó) nếu thuộc tính "dừng" là trên

Trong mọi trường hợp, bằng cách tạo stdoutmột đường ống trong cả hai giải pháp và do hai lệnh độc lập xuất thông báo đầu ra và thông báo lỗi, điều này sẽ ảnh hưởng đến bộ đệm đầu ra và thứ tự các thông báo lỗi và đầu ra được hiển thị.


Tôi nghĩ rằng tee thứ hai của bạn đang thiếu một chuyển hướng đến stderr. Nó sẽ là:tee -a log >&2 3>&-
richvdh

5

Tôi biết đây là một bài viết cũ, nhưng tại sao không làm điều này?

echo "hi" >> log.txt #stdout -> log
echo "hi" | tee -a log.txt #stdout -> log & stdout
echo "hi" &>> log.txt #stdout & stderr -> log
echo "hi" |& tee -a log.txt #stdout & stderr -> log & stdout

Và tất nhiên, nếu bạn muốn thiết bị xuất chuẩn, bạn có thể in thường xuyên.

Bạn có thể làm điều này với bất kỳ sự kết hợp các luồng nào bạn muốn, chỉ cần sử dụng hai lệnh cơ bản đó.

Tôi biết tôi đã đến đây và không nhận được câu trả lời dễ hiểu / thực hiện, hy vọng điều này sẽ giúp ích cho người khác đang gặp khó khăn.

Nhân tiện, đối với các noobs ngoài đó như bản thân trước đây của tôi, tất cả các teelệnh thực hiện là đầu ra stdin cho cả stdout và (các) tệp được chỉ định làm đối số tiếp theo. -alà viết tắt của append, vì vậy bạn không ghi đè lên tệp với mỗi lần sử dụng lệnh. Nếu bạn có thêm câu hỏi, tôi thấy đây là một tài nguyên rất hữu ích để nhanh chóng học bash.


1
Cảm ơn đã đóng góp. Mặt khác, tôi đã hoàn toàn quên mất những gì tôi đã cố gắng làm :-)
adarshr

1
+1 để đưa ra nhiều ví dụ, đẹp và đơn giản, tee.
Tim

2

Một cách khác để làm điều đó là sử dụng chuyển hướng trong các chức năng.

#!/bin/bash

function1 () {
    echo 'STDOUT from function 1'
    echo 'STDERR from function 1' >&2
}

function2 () {
    echo 'STDOUT from function 2'
    echo 'STDERR from function 2' >&2
}


function3 () {
    echo 'STDOUT from function 3'
    echo 'STDERR from function 3' >&2
}

main() {
    function1
    function2
    function3
}

main 2>&1 |tee log.txt

Ở đây chúng ta có một mainhàm gọi tất cả các hàm khác. Bây giờ chuyển hướng STDOUTSTDERRcác mainchức năng để tee.


IMHO đây là cách sạch nhất để làm điều này, ít nhất là đối với các trường hợp đơn giản. Cảm ơn.
ACK_stoverflow
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.