2009-01-07 31 views
11

Ngay bây giờ tôi đang sử dụng exec để chuyển hướng stderr đến một bản ghi lỗi vớiNối văn bản để stderr chuyển hướng trong bash

exec 2>> ${errorLog} 

Nhược điểm duy nhất là tôi phải bắt đầu mỗi lần chạy với timestamp từ exec chỉ đẩy văn bản thẳng vào tệp nhật ký. Có cách nào để chuyển hướng stderr nhưng cho phép tôi để thêm văn bản vào nó, chẳng hạn như một dấu thời gian?

Trả lời

16

Điều này rất thú vị. Tôi đã hỏi một anh chàng biết bash khá tốt, và ông nói với tôi theo cách này:

foo() { while IFS='' read -r line; do echo "$(date) $line" >> file.txt; done; }; 

Thứ nhất, tạo ra một chức năng đọc một dòng đầu vào nguyên liệu từ thiết bị nhập chuẩn, trong khi việc chuyển nhượng để IFS làm cho nó doesn' t bỏ qua khoảng trống. Sau khi đọc một dòng, nó sẽ xuất nó với dữ liệu thích hợp được thêm vào trước. Sau đó, bạn phải nói bash để chuyển hướng stderr vào hàm đó:

exec 2> >(foo) 

Mọi thứ bạn viết vào stderr giờ đây sẽ trải qua hàm foo. Lưu ý khi bạn làm điều đó trong một trình bao tương tác, bạn sẽ không thấy lời nhắc nữa, vì nó được in thành tiêu chuẩn, và đọc trong foo là dòng đệm :)

+0

$ foo() {while IFS = '' read-line; làm echo "$ (date) $ line" >> file.txt; làm xong; }; $ exec 2>> (foo) Cảnh báo: Chương trình '/ bin/bash' gặp sự cố. whoops – Peter

+0

Nhưng nếu tôi thay đổi thành: echo 2 | tee> (foo), sau đó nó hoạt động tốt. – Peter

+0

Trong câu hỏi, mỗi dòng được nối vào một tệp đã được mở. Trong câu trả lời, tệp nhật ký được mở cho mỗi dòng. Và tìm kiếm đến cuối tập tin cũng cần thiết. Nó có thể là tốt hơn để làm một 'exec' thứ hai trong' foo'. – ceving

1

Bạn có thể đơn giản chỉ cần sử dụng:

exec 1> >(sed "s/^/$(date '+[%F %T]'): /" | tee -a ${LOGFILE}) 2>&1 

này sẽ không hoàn toàn giải quyết vấn đề của bạn về Prompt không được hiển thị (ITT sẽ hiển thị sau khi một thời gian ngắn, nhưng không phải thời gian thực, vì đường ống sẽ lưu một số dữ liệu ...), nhưng sẽ hiển thị đầu ra 1: 1 trên stdout cũng như trong tệp.

Vấn đề duy nhất là, mà tôi không thể giải quyết được, để làm điều này từ một chức năng, vì đó sẽ mở ra một subshell, nơi exec là vô ích cho các chương trình chính ...

+0

Bằng cách này tất cả các dòng có được cùng một dấu thời gian? – ceving

-1
cat q23123 2> tmp_file ;cat tmp_file | sed -e "s/^/$(date '+[%F %T]'): /g" >> output.log; rm -f tmp_file 
0

này ví dụ chuyển hướng stdout và stderr mà không mất stdr gốc và stderr. Ngoài ra các lỗi trong trình xử lý stdout được ghi vào trình xử lý stderr. Các bộ mô tả tập tin được lưu trong các biến và đóng trong các tiến trình con. Bash cẩn thận, không có va chạm nào xảy ra.

#! /bin/bash 

stamp() 
{ 
    local LINE 
    while IFS='' read -r LINE; do 
    echo "$(date '+%Y-%m-%d %H:%M:%S,%N %z') $$ $LINE" 
    done 
} 

exec {STDOUT}>&1 
exec {STDERR}>&2 
exec 2> >(exec {STDOUT}>&-; exec {STDERR}>&-; exec &>> stderr.log; stamp) 
exec > >(exec {STDOUT}>&-; exec {STDERR}>&-; exec >> stdout.log; stamp) 

for n in $(seq 3); do 
    echo loop $n >&$STDOUT 
    echo o$n 
    echo e$n >&2 
done 

Điều này yêu cầu phiên bản Bash hiện tại nhưng nhờ ngày Shellshock người ta có thể dựa vào điều này ngày nay.

Các vấn đề liên quan