chuyển hướng và đăng nhập tập lệnh


8

Tôi đang cố gắng thu dọn các đoạn mã sau, mục tiêu thiết kế là ghi nhật ký tất cả đầu ra từ một tập lệnh và không nên là một trình bao bọc. Ít dòng là tốt hơn.

Tôi không quan tâm đến đầu vào của người dùng (ở giai đoạn này), các tập lệnh đích được chạy không tương tác.

Đoạn trích cần phải

  • xuất ra thiết bị xuất chuẩn để đăng nhập và luôn lặp lại bảng điều khiển
  • đầu ra stderr để đăng nhập và echo để gỡ lỗi iff console
  • thông điệp stderr nên được thêm tiền tố vào dấu thời gian và tính hữu dụng khác

Hiện tại tôi có những điều sau đây chỉ kiểm tra theo các phiên bản bash gần đây (4.2+?) Như trong Ubuntu chính xác, nhưng hoạt động sai trên CentOS6.

DEBUG_LOG="${0##*/}.log"

# copy stdout to log always and echo to console
exec >  >(tee -a ${DEBUG_LOG})           

# copy stderr to log only, unless debugging is enabled
[ $DEBUG_TEST = "true" ] \
  && exec 2> >(tee -a ${DEBUG_LOG} >&2) \
  || exec 2>> ${DEBUG_LOG}

Thì đây...

# Expand escaped characters, wrap at 70 chars on spaces, 
# and indent wrapped lines
msg_log() { 
  echo -e "$(date +%T) ${0##*/}: $1" \
    | fold -w70 -s | sed '2~1s/^/  /' >&2; 
}
msg_con() { 
  if [ "${DEBUG_TEST}" = "true" ]; then 
    msg_log "$1"
  else
    echo -e "$1" | fold -w70 -s | sed '2~1s/^/  /'; 
  fi
}

Thay vì echotôi có thể gọi một trong những thủ tục tin nhắn đó, vd msg_con "hello world".
Ngoài ra đầu ra tập lệnh sau đó sẽ đi đến thiết bị lỗi chuẩn bằng cách đặt làm biến môi trường tại thời điểm cuộc gọi, ví dụ :  DEBUG_TEST=true myscript.

Tôi đã đọc rằng exec có thể không hoạt động trong một số shell như busybox. Có một sự kết hợp mkfifo và ngã ba tại https://stackoverflow.com/a/5200754 có chức năng tương tự nhưng tôi không muốn sử dụng ngã ba trừ khi thực sự cần thiết.

Vui lòng thích các ví dụ bash, nhưng một cái gì đó hoạt động theo sh hoặc dễ mang theo hơn sẽ tốt hơn. Có ý kiến ​​gì không?

Câu trả lời:


1
function startLogging {
    exec > >(gawk -v pid=$$ '{ print strftime("%F-%T"),pid,$0; fflush(); }' | tee -a $logfile)
    [ ! -z "$DEBUG" ] && exec 2>&1 || exec 2> >(gawk -v pid=$$ '{ print strftime("%F-%T"),pid,$0; fflush(); }' >>$logfile)
    echo "=== Log started for $$ at $(date +%F-%T) ==="
}

Bạn cần phải có $ logfile được đặt thành một cái gì đó


Điều này thật tuyệt, theo cách tôi đang đọc, bạn sử dụng gawk để thêm các tiêu đề thư. Điều đó sẽ có tác dụng phụ bổ sung là thêm chúng vào đầu ra lệnh.
Glenn

Lý do sử dụng gawk để thêm dấu thời gian (và id quá trình) vào mỗi dòng nhật ký là vì nó sẽ được thực thi mỗi khi đầu ra được ghi và do đó cập nhật dấu thời gian. Ngoài ra, điều quan trọng là sử dụng gawk và không awk vì tôi nghĩ rằng hàm strftime là một phần mở rộng GNU.
Angelo

0

exec > filenamenên hoạt động trong sh và nó thực sự hoạt động trong busybox v1.15.3 (tháng 11 năm 2011). Nhưng sự thay thế quá trình >(command)là không thể thực hiện được vì nó là phần mở rộng bash. Chỉ cần tránh sử dụng nó trong các kịch bản. Tại sao >>không đủ cho bạn?

exec 1>>${DEBUG_LOG}
exec 2>>${DEBUG_LOG}

Một giải pháp khác là chỉ định chuyển hướng bên ngoài các tập lệnh của bạn. Khi tập lệnh của bạn được gọi trong nền (theo cron hoặc tập lệnh hệ thống, v.v.), chúng sẽ được gọi như thế này

./my_script 1>>${DEBUG_LOG} 2>>${DEBUG_LOG}

Khi bạn gọi tập lệnh theo cách thủ công và bạn muốn xem đầu ra, chỉ cần gọi nó mà không chuyển hướng.


1
Người hỏi câu hỏi muốn đầu ra của tập lệnh đi đến cả bàn điều khiển và tệp nhật ký.

0

Hai ví dụ này sẽ làm những gì mục tiêu đã nêu của bạn là

echo -n $(date) >> $DEBUG_LOG
command 2>&1 | tee -a $DEBUG_LOG

hoặc là

echo -n $(date) >> $DEBUG_LOG
command >> $DEBUG_LOG 2>&1

0

Bạn có thể sử dụng teelệnh hoặc scriptlệnh cả hai đều thực sự hữu ích.


kịch bản có vẻ hay, nhưng không thực sự làm những gì tôi cần, hành vi phải sửa đổi trong thời gian chạy.
Glenn
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.