Làm cách nào để gửi tất cả đầu ra tới `logger` trong vỏ POSIX?


10

Tôi muốn đăng nhập đầu ra tiêu chuẩn và lỗi tiêu chuẩn riêng biệt trong .xprofileviệc sử dụng logger. Trong Bash tôi nghĩ rằng nó sẽ trông giống như thế này:

exec 1> >(logger --priority user.notice --tag $(basename $0)) \
     2> >(logger --priority user.error --tag $(basename $0))

Làm thế nào tôi có thể làm điều đó theo cách tương thích POSIX /bin/sh ?

Câu trả lời:


10

Không có POSIX tương đương. Bạn chỉ có thể thực hiện chuyển hướng với exec, không phải là một ngã ba. Một đường ống đòi hỏi một cái nĩa, và vỏ chờ cho đứa trẻ hoàn thành.

Một giải pháp là đặt tất cả mã của bạn vào một hàm.

all_my_code () {
  
}
{ all_my_code |
  logger --priority user.notice --tag "$(basename "$0")"; } 2>&1 | 
  logger --priority user.error --tag "$(basename "$0")"

(Điều này cũng ghi lại bất kỳ lỗi nào từ phiên bản đầu ra của logger sang phiên bản stderr. Bạn có thể tránh điều này với việc xáo trộn mô tả tệp nhiều hơn.)

Nếu bạn muốn shell cha thoát ngay cả khi các loggertiến trình vẫn đang chạy, hãy đặt &ở cuối các lệnh logger.

{ all_my_code |
  logger --priority user.notice --tag "$(basename "$0")" & } 2>&1 | 
  logger --priority user.error --tag "$(basename "$0")" &

Ngoài ra, bạn có thể sử dụng ống có tên.

pipe_dir=$(mktemp -d)
mkfifo "$pipe_dir/out" "$pipe_dir/err"
<"$pipe_dir/out" logger --priority user.notice --tag "$(basename "$0")" &
<"$pipe_dir/err" logger --priority user.error --tag "$(basename "$0")" &
exec >"$pipe_dir/out" 2>"$pipe_dir/err" 

rm -r "$pipe_dir"

Điều đó sẽ xuất hiện trong syslog dưới dạng hai mục (out & err) cho toàn bộ tập lệnh. Ví dụ trong câu hỏi sẽ có một (hoặc hai) mục nhập cho mỗi lệnh.
DarkHeart

@DarkHeart Tôi không hiểu bình luận của bạn. Mã trong câu hỏi và cả hai giải pháp tôi đề xuất đều chạy cùng một số lượng phiên bản loggervà chuyển cùng một đầu vào cho mỗi trong số chúng.
Gilles 'SO- đừng trở nên xấu xa'

xin lỗi, lỗi của tôi
DarkHeart

1
Điều này có vẻ đơn giản hơn , vì vậy tôi sẽ đi với giải pháp đường ống được đặt tên của bạn.
l0b0

9

Thay thế lệnh / quy trình POSIX


_log()( x=0
    while  [ -e "${TMPDIR:=/tmp}/$$.$((x+=1))" ]
    do     continue; done        &&
    mkfifo -- "$TMPDIR/$$.$x"    &&
    printf %s\\n "$TMPDIR/$$.$x" || exit
    exec >&- >/dev/null
    {  rm -- "$TMPDIR/$$.$x"
       logger --priority user."$1" --tag "${0##*/}"
    }  <"$TMPDIR/$$.$x" &
)   <&- </dev/null

Bạn sẽ có thể sử dụng như thế:

exec >"$(_log notice)" 2>"$(_log error)"

Đây là phiên bản sử dụng mktemplệnh:

_log()( p=
    mkfifo "${p:=$(mktemp -u)}"    &&
    printf %s "$p"                 &&
    exec  <&- >&- <>/dev/null >&0  &&
    {   rm "$p"
        logger --priority user."$1" --tag "${0##*/}"
    }   <"$p" &
)

... không giống nhau lắm, ngoại trừ việc nó cho phép mktempchọn tên tệp cho bạn. Điều này hoạt động bởi vì sự thay thế quá trình không có nghĩa là kỳ diệu và hoạt động theo cách rất giống với thay thế lệnh . Thay vì thay thế sự mở rộng bằng giá trị của lệnh chạy bên trong nó như thay thế lệnh , thay thế quá trình thay thế nó bằng tên của một liên kết hệ thống tập tin nơi có thể tìm thấy đầu ra.

Trong khi vỏ POSIX không cung cấp một hệ quả trực tiếp cho một điều như vậy, việc mô phỏng nó được thực hiện rất đơn giản. Tất cả những gì bạn cần làm là tạo một tệp, in tên của nó thành tiêu chuẩn thay thế lệnh và trong nền của cùng một lệnh chạy lệnh của bạn sẽ xuất ra tệp đó. Bây giờ bạn có thể chuyển hướng vào giá trị của bản mở rộng đó - chính xác như bạn làm với quy trình thay thế. Và vì vậy, vỏ POSIX cung cấp tất cả các công cụ bạn cần tất nhiên - tất cả những gì được yêu cầu là bạn đưa chúng vào sử dụng theo cách phù hợp với bạn.

Cả hai phiên bản trên đều đảm bảo rằng chúng phá hủy liên kết hệ thống tập tin đến các đường ống mà chúng tạo / sử dụng trước khi sử dụng chúng. Điều này có nghĩa là không có yêu cầu dọn dẹp sau thực tế, và quan trọng hơn, các luồng của chúng chỉ có sẵn cho các quy trình mở chúng ban đầu - và vì vậy các liên kết hệ thống tệp của chúng không thể được sử dụng như một phương tiện để theo dõi hoạt động đăng nhập của bạn. Để lại các liên kết fs của họ trong hệ thống tập tin là một lỗ hổng bảo mật tiềm năng.


Một cách khác là bọc nó. Nó có thể được thực hiện từ trong kịch bản.

x=${x##*[!0-9]*}
_log(){ 
    logger --priority user."$1" --tag "${0##*/}"
}   2>/dev/null >&2

cd ../"$PPID.$x" 2>/dev/null &&
trap 'rm -rf -- "${TMPDIR:-/tmp}/$PPID.$x"' 0 || 
{   until cd -- "${TMPDIR:=/tmp}/$$.$x"
    do    mkdir -- "$TMPDIR/$$.$((x+=1))"
    done  && 
    x=$x "$0" "$@" | _log notice
    exit
}   2>&1 | _log error

Điều đó về cơ bản sẽ cho phép tập lệnh của bạn tự gọi nếu nó chưa có và giúp bạn có một thư mục công việc trong temp để khởi động.


1
Xong rồi , cảm ơn bạn!
l0b0

@ l0b0 - Tôi sắp cập nhật một loại khác như thế này ... Nó có mục đích chung hơn, và cuối cùng tôi đã xoay quanh để cung cấp cho nó khả năng xử lý một số tùy chọn có liên quan đến i / o mô tả / tệp.
mikeerv

@ l0b0 - nếu bạn muốn sử dụng mktempvà các lệnh không chuẩn khác, nó có thể là : _log()( p=; mkfifo "${p:=$(mktemp -u)}"; printf %s "$p"; exec <&- >&- <>/dev/null >&0; { rm "$p"; logger --priority user."$1" --tag "${0##*/}"; } <"$p" &). Tôi đã viết nó bằng ngôn ngữ lệnh hoàn toàn di động theo mọi cách - ngoại trừ của riêng bạn. Ngoài ra, basenamekhông phải là một tiện ích rất hữu ích. "${0##*/}"là cả mạnh mẽ hơn và nhanh hơn.
mikeerv

Tôi đã thay đổi nó vì tôi chỉ cần nó hoạt động trên các nền tảng hiện đại; vấn đề chính là .xprofile được thực hiện với sh.
l0b0

1
@Wildcard - chỉ một phút và tôi sẽ cố gắng sắp xếp phần đầu tiên của câu hỏi, nhưng câu trả lời cho câu hỏi thứ hai là có: trường hợp cạnh là một zshw / multios được kích hoạt. Đối với phần đầu tiên : { this; can\'t; happen; before; } < this. cái đó có giúp ích không?
mikeerv 15/03/2016
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.