Buộc tập lệnh bash sử dụng tee mà không cần đường ống từ dòng lệnh


20

Tôi có một tập lệnh bash có nhiều đầu ra và tôi muốn thay đổi tập lệnh đó (không tạo tập lệnh mới) để sao chép tất cả đầu ra vào một tập tin, giống như nó sẽ xảy ra nếu tôi chuyển nó qua tee.

Tôi có một tập tin script.sh :

#!/bin/bash
init
do_something_that_outputs_stuff_to_STDOUT
launch_applications_that_output_to_STDOUT
fini

và tôi muốn tạo một bản sao của STDOUT thành tập tin script.log mà không phải gõ ./script.sh | tee script.logmỗi lần.

Cảm ơn, Tom


Tôi xin lỗi vì đã không nói điều này sớm hơn, nhưng kịch bản khá dài, đó là lý do tại sao tôi đang tìm kiếm một giải pháp đơn giản. Đang áp dụng | tee đến từng dòng là một chút quá nhiều.
Tom

Câu trả lời:


15

Tôi không thể làm cho một lớp lót rất đơn giản của Dennis hoạt động, vì vậy đây là một phương pháp phức tạp hơn nhiều. Tôi sẽ thử đầu tiên của anh ấy.

Như đã đề cập, bạn có thể sử dụng exec để chuyển hướng lỗi & tiêu chuẩn ra cho toàn bộ tập lệnh. Giống như vậy:
exec > $LOGFILE 2>&1 Điều này sẽ xuất tất cả các thiết bị xuất chuẩn và thiết bị xuất chuẩn thành $ LOGFILE.

Bây giờ, vì bạn muốn hiển thị bảng điều khiển này cho bảng điều khiển cũng như logfile, bạn cũng sẽ phải sử dụng một ống có tên để thực thi để ghi và đọc từ đó.
(Về mặt kỹ thuật, một lớp lót của Dennis cũng thực hiện điều này, mặc dù rõ ràng theo một cách khác) Bản thân đường ống được tạo ra mkfifo $PIPEFILE. Sau đó làm như sau.

# Bắt đầu viết tee vào logfile, nhưng kéo đầu vào của nó từ đường ống được đặt tên của chúng tôi.
tee $ LOGFILE <$ PIPEFILE &

# chụp ID tiến trình của tee cho lệnh chờ.
TEEPID = $!

# chuyển hướng phần còn lại của thiết bị xuất chuẩn và thiết bị xuất chuẩn đến đường ống được đặt tên của chúng tôi.
thực thi> $ PIPEFILE 2> & 1

echo "Thực hiện các lệnh của bạn ở đây"
echo "Tất cả các tiêu chuẩn của họ sẽ nhận được teed."
echo "Lỗi tiêu chuẩn của họ cũng vậy"> & 2

# đóng mô tả tập tin stderr và stdout.
thực hiện 1> & - 2> & -

# Đợi tee kết thúc vì bây giờ đầu kia của ống đã đóng.
chờ $ TEEPID

Nếu bạn muốn kỹ lưỡng, bạn có thể tạo và hủy tệp đường ống được đặt tên ở đầu và cuối tập lệnh của mình.

Để ghi lại, tôi đã lượm lặt được hầu hết những điều này từ một bài đăng trên blog rất nhiều thông tin của một anh chàng ngẫu nhiên: ( Phiên bản lưu trữ )


Điều này dường như không hoạt động trong cygwin. :-(
docwhat

Bài này làm một công việc tốt của giáo dục. Cảm ơn rât nhiều.
Felipe Alvarez

27

Chỉ cần thêm phần này vào phần đầu của tập lệnh của bạn:

exec > >(tee -ia script.log)

Điều đó sẽ nối tất cả đầu ra được gửi đến thiết bị xuất chuẩn vào tệp script.log, để lại các nội dung trước đó. Nếu bạn muốn bắt đầu làm mới mỗi khi tập lệnh được chạy, chỉ cần thêm rm script.logngay trước execlệnh đó hoặc xóa lệnh -akhỏi teelệnh.

Các -itùy chọn nguyên nhân teeđể bỏ qua tín hiệu ngắt và có thể cho phép teeđể đón một bộ đầu ra hoàn chỉnh hơn.

Thêm dòng này để cũng bắt tất cả các lỗi (trong một tệp riêng):

exec 2> >(tee -ia scripterr.out)

Khoảng cách giữa nhiều >biểu tượng rất quan trọng.


Giải pháp rất thú vị.
ℝaphink

2
Đây là một cách thực sự thanh lịch, so với tất cả các crap tôi đã đăng. Nhưng khi tôi tạo một tập lệnh có hai dòng trong đó, nó bị treo và không bao giờ thoát đúng.
Christopher Karel


GNU bash, phiên bản 3.2.25 (1) là một phần của bản cài đặt RHEL5.3. Có vẻ như đây là phiên bản mới nhất từ ​​kho chính thức.
Christopher Karel

Tôi vừa thử nó dưới cygwin trong Bash 3.2.49 (23) -release và nhận được lỗi mô tả tập tin. Mặc dù vậy, tôi làm việc trong Bash 4.0.33 (1) trong bản phát hành Ubuntu 9.10, vì vậy đây có thể là một điều của Bash 4.
Tạm dừng cho đến khi có thông báo mới.

6

Đây là phiên bản kết hợp của câu trả lời được đăng bởi Dennis Williamson trước đó. Nối cả err & std out vào script.log theo đúng thứ tự.

Thêm dòng này vào đầu tập lệnh của bạn:

exec > >(tee -a script.log) 2>&1

Lưu ý không gian giữa các >dấu hiệu. Hoạt động với tôi trên GNU bash, phiên bản 3.2.25 (1) -release (x86_64-redhat-linux-gnu)


5

Tôi cho rằng một cách tiếp cận khác là như thế này:

#!/bin/bash

# start grouping at the top
{ 
    # your script goes here
    do_something_that_outputs_stuff_to_STDOUT
    launch_applications_that_output_to_STDOUT

# and at the bottom, redirect everything from the grouped commands
} 2>&1 | tee script.log 

3

Nếu bạn muốn có một bản sao của đầu ra, bạn có thể sử dụng teecách này:

  #!/bin/bash
  init
  do_something_that_outputs_stuff_to_STDOUT | tee script.log
  launch_applications_that_output_to_STDOUT | tee -a script.log
  fini

Điều này sẽ chỉ đăng nhập stdout vào script.log tuy nhiên. Nếu bạn muốn đảm bảo cả stderr và stdout đều được chuyển hướng, hãy sử dụng:

  #!/bin/bash
  init
  do_something_that_outputs_stuff_to_STDOUT 2>&1 | tee script.log
  launch_applications_that_output_to_STDOUT 2>&1 | tee -a script.log
  fini

Bạn thậm chí có thể làm cho nó đẹp hơn một chút với một chức năng nhỏ:

  #!/bin/bash

  LOGFILE="script.log"
  # Wipe LOGFILE if you don't want to add to it at each run
  rm -f "$LOGFILE"

  function logcmd() {
        local cmd="$1" logfile=${LOGFILE:-script.log} # Use default value if unset earlier

        # Launch command, redirect stderr to stdout and append to $logfile
        eval '$cmd' 2>&1 | tee -a "$logfile"
  }

  init
  logcmd "do_something_that_outputs_stuff_to_STDOUT"
  logcmd "launch_applications_that_output_to_STDOUT"
  fini

Câu trả lời tốt. Nếu anh ấy thực sự chỉ quan tâm đến thiết bị xuất chuẩn, tôi sẽ bỏ 2>&1qua và chỉ đưa nó đến tee.
DaveParillo

Đó là sự thật, tôi chỉ bao gồm stderr bởi vì câu trả lời trước đó từ Igor quan tâm để chuyển hướng nó và tôi nghĩ rằng đó là một ý tưởng tốt.
ℝaphink

1

Bạn chỉ cần sử dụng cái này:

script logfile.txt
your script or command here

Điều này xuất ra mọi thứ cho nhật ký đó, mọi thứ, cũng như hiển thị nó trên màn hình. Nếu bạn muốn đầu ra FULL, đây là cách thực hiện.

Và sau đó bạn có thể phát lại kịch bản nếu bạn lười biếng.


Có thể là tốt để lưu ý rằng đó scriptlà một gói, ví dụ. sudo apt-get install scriptđể cài đặt nó trên các bản phân phối có hương vị Debian , ngoài ra script -ac 'command opts' ~/Documents/some_log.scriptcó thể được xem xét trong một thiết bị đầu cuối thông qua một cái gì đó như strings ~/Documents/some_log.script | more; stringslà một cách đơn giản để vệ sinh trước một số thứ được script tiêm để cho phép các phương pháp chơi lại / xem dễ dàng hơn. Nếu không, một câu trả lời chắc chắn @Phishy, ​​vì scriptcũng bảo tồn những thứ tương tác.
S0AndS0

0
#!/bin/bash
init
do_something_that_outputs_stuff_to_STDOUT > script.log 2>&1
launch_applications_that_output_to_STDOUT >> script.log 2>&1
fini

Bạn có thể xem thêm về cách thức hoạt động tại đây: http://www.xaprb.com/blog/2006/06/06/what-does-devnull-21-mean/


1
Tôi đã thêm một giây> vào dòng thứ hai trong câu trả lời của Igor để nó không xóa sạch nhật ký được viết ở dòng đầu tiên.
Doug Harris

1
Anh ta muốn một bản sao, vì vậy anh ta cần phải sử dụng tee.
ℝaphink

@Raphink: Đúng vậy :)
Tom
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.