Làm cách nào để xuất văn bản ra cả màn hình và tệp bên trong tập lệnh shell?


49

Hiện tại tôi có một tập lệnh shell để ghi thông điệp vào một tệp nhật ký như thế này:

log_file="/some/dir/log_file.log"
echo "some text" >> $log_file
do_some_command
echo "more text" >> $log_file
do_other_command

Khi thực thi tập lệnh này, không có đầu ra cho màn hình và vì tôi đang kết nối với máy chủ thông qua putty, tôi phải mở một kết nối khác và thực hiện "tail -f log_file_path.log", vì tôi không thể chấm dứt hoạt động script và tôi muốn xem đầu ra trong thời gian thực.

Rõ ràng, điều tôi muốn là các tin nhắn văn bản được in trên màn hình và thành tệp, nhưng tôi muốn thực hiện nó trong một dòng, không phải hai dòng, một trong số đó không có chuyển hướng đến tệp.

Làm thế nào để đạt được điều này?

Câu trả lời:


71

Những công việc này:

command | tee -a "$log_file"

teelưu đầu vào vào một tệp (sử dụng -ađể chắp thêm thay vì ghi đè) và sao chép đầu vào thành đầu ra tiêu chuẩn.


8

Bạn có thể sử dụng tài liệu ở đây và. nguồn nó cho một mô hình tổng hợp hiệu quả, thân thiện với POSIX.

. 8<<-\IOHERE /proc/self/fd/8

command
 
fn() { declaration ; } <<WHATEVER
# though a nested heredoc might be finicky
# about stdin depending on shell
WHATEVER
cat -u ./stdout | ./works.as >> expect.ed
IOHERE

Khi bạn mở heredoc, bạn báo hiệu shell bằng mã thông báo đầu vào IOHERE rằng nó sẽ chuyển hướng đầu vào của nó đến bộ mô tả tệp mà bạn chỉ định cho đến khi nó gặp đầu kia của mã thông báo giới hạn của bạn. Tôi đã nhìn xung quanh nhưng tôi chưa thấy nhiều ví dụ về việc sử dụng số fd chuyển hướng như tôi đã trình bày ở trên kết hợp với toán tử heredoc, mặc dù cách sử dụng của nó được quy định rõ ràng trong hướng dẫn lệnh shell cơ bản POSIX. Hầu hết mọi người chỉ hướng nó vào stdin và bắn, nhưng tôi thấy việc tìm nguồn cung cấp tập lệnh theo cách này có thể giữ cho stdin miễn phí và các ứng dụng cấu thành không phàn nàn về các đường dẫn I / o bị chặn.

Nội dung của heredoc được truyền trực tiếp đến bộ mô tả tệp mà bạn chỉ định, sau đó được hiểu là mã shell và được thực thi bởi. dựng sẵn, nhưng không phải không chỉ định một đường dẫn cụ thể cho. . Nếu đường dẫn / Proc / self cung cấp cho bạn sự cố, hãy thử / dev / fd / n hoặc / Proc / $$. Nhân tiện, phương pháp này cũng hoạt động trên các đường ống:

cat ./*.sh | . /dev/stdin

Có lẽ ít nhất là không khôn ngoan như nó trông. Tất nhiên, bạn có thể làm tương tự với sh, nhưng mục đích của nó là thực thi trong môi trường shell hiện tại, đó có thể là những gì bạn muốn, và, tùy thuộc vào shell của bạn, có nhiều khả năng làm việc với một di sản hơn với một ống ẩn danh tiêu chuẩn.

Dù sao, như bạn có thể nhận thấy, tôi vẫn chưa trả lời câu hỏi của bạn. Nhưng nếu bạn nghĩ về nó, giống như cách di truyền tất cả mã của bạn vào. Nó cũng cung cấp cho bạn một điểm duy nhất, đơn giản,:

. 5<<EOIN /dev/fd/5 |\ 
    tee -a ./log.file | cat -u >$(tty)
script
 
more script
EOIN

Vì vậy, tất cả các thiết bị đầu cuối đầu cuối từ bất kỳ mã nào được thực thi trong di sản của bạn đều được lấy từ. như một vấn đề tất nhiên và có thể dễ dàng thoát khỏi một đường ống duy nhất. Tôi đã bao gồm cuộc gọi mèo không có bộ đệm vì tôi không rõ về hướng xuất phát hiện tại, nhưng nó có thể là dư thừa (gần như chắc chắn nó vẫn được viết như vậy) và đường ống có thể kết thúc ngay tại tee.

Bạn cũng có thể đặt câu hỏi về dấu ngoặc kép bị thiếu trong ví dụ thứ hai. Phần này rất quan trọng để hiểu trước khi bạn nhảy vào và có thể cung cấp cho bạn một vài ý tưởng về cách sử dụng nó. Một bộ giới hạn heredoc được trích dẫn (cho đến nay chúng tôi đã sử dụng IOHERE và EOIN, và lần đầu tiên tôi trích dẫn bằng dấu gạch chéo ngược, mặc dù các trích dẫn 'đơn' hoặc "kép" sẽ phục vụ cùng một mục đích) sẽ ngăn chặn việc thực hiện bất kỳ việc mở rộng tham số nào trên nội dung, nhưng một bộ giới hạn không được trích dẫn sẽ để lại nội dung của nó mở rộng. Hậu quả của điều này khi di truyền của bạn là. nguồn gốc là kịch tính:

. 3<<HD ${fdpath}/3
: \${vars=$(printf '${var%s=$((%s*2))},' `seq 1 100`)} 
HD
echo $vars
> 4,8,12 
echo $var1 $var51
> 4 104

Bởi vì tôi đã không trích dẫn bộ giới hạn heredoc, shell đã mở rộng nội dung khi nó đọc nó và trước khi phục vụ bộ mô tả tệp kết quả. để thực thi. Điều này về cơ bản dẫn đến các lệnh được phân tích cú pháp hai lần - những lệnh có thể mở rộng bằng mọi cách. Vì dấu gạch chéo ngược được trích dẫn khi mở rộng tham số $ vars, shell đã bỏ qua khai báo của nó trong lần truyền đầu tiên và chỉ xóa dấu gạch chéo ngược để toàn bộ nội dung mở rộng printf có thể được đánh giá bằng null khi. nguồn kịch bản trên đường chuyền thứ hai.

Chức năng này về cơ bản chính xác là những gì mà vỏ bọc eval nguy hiểm có thể cung cấp, ngay cả khi trích dẫn dễ xử lý hơn trong một di sản so với eval, và có thể nguy hiểm như nhau. Trừ khi bạn lên kế hoạch cẩn thận, tốt nhất là nên trích dẫn bộ giới hạn "EOF" như một vấn đề của thói quen. Chỉ cần nói.

EDIT: Eh, tôi đang nhìn lại điều này và nghĩ rằng nó hơi quá sức. Nếu TẤT CẢ bạn cần làm là nối nhiều đầu ra thành một ống thì phương pháp đơn giản nhất là sử dụng:

{ or ( command ) list ; } | tee -a ea.sy >>pea.sy

Các curlies sẽ cố gắng chạy nội dung trong shell hiện tại trong khi các parens sẽ tự động thoát ra. Tuy nhiên, bất cứ ai cũng có thể nói với bạn điều đó và, ít nhất là theo ý kiến ​​của tôi ,. Giải pháp heredoc là thông tin có giá trị hơn nhiều, đặc biệt là nếu bạn muốn hiểu cách thức hoạt động của vỏ.

Chúc vui vẻ!


3

Tôi tìm thấy câu trả lời này trong khi tìm cách sửa đổi tập lệnh cài đặt để viết nhật ký cài đặt.

Kịch bản của tôi đã có đầy đủ các câu lệnh echo như:

echo "Found OLD run script $oldrunscriptname"
echo "Please run OLD tmunsetup script first!"

Và tôi không muốn một câu lệnh tee chạy nó (hoặc một kịch bản khác để gọi câu lệnh hiện có bằng một cú phát bóng), vì vậy tôi đã viết điều này:

#!/bin/bash
# A Shell subroutine to echo to screen and a log file

LOGFILE="junklog"

echolog()
(
echo $1
echo $1 >> $LOGFILE
)


echo "Going"
echolog "tojunk"

# eof

Vì vậy, bây giờ trong tập lệnh gốc của tôi, tôi chỉ có thể thay đổi 'echo' thành 'echolog' nơi tôi muốn đầu ra trong một tệp nhật ký.

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.