Tại sao `exec 2> & 1` không thành công trong tập lệnh shell bourne này?


7

Tôi đang chuyển một tập lệnh ksh cũ sang shell Bourne. Kịch bản ksh cũ chứa mã sau:

#!/bin/sh

tmpLog=/var/tmp/logfile.$$

exec 1> $tmpLog
exec 2>&1

eval $*
another_command_1
another_command_2

Từ những gì tôi đọc được, có vẻ như hai câu lệnh exec này được dùng để thực thi $ *, Another_command_1, Another_command_2 và tất cả các lệnh sau; và sau đó chuyển hướng tất cả STDERR và STDOUT từ các lệnh đó vào /var/tmp/logfile.$$. Tuy nhiên, khi tôi chạy nó trong một kịch bản thì kịch bản thất bại sau đó exec 2>&1.

stefanl@host:~ $ sh -xv ./output.sh echo "Hello"
#!/bin/sh

tmpLog=/var/tmp/logfile.$$
+ tmpLog=/var/tmp/logfile.39918

exec 1> $tmpLog
+ exec
exec 2>&1
+ exec
stefanl@host:~ $

Và khi tôi chạy nó trên dòng lệnh, shell của tôi đóng băng sau khi tôi thực thi exec 2>&1:

stefanl@host:~ $ tmpLog=/var/tmp/logfile.$$
stefanl@host:~ $ exec 1> $tmpLog
stefanl@host:~ $ exec 2>&1
### FREEZE ###

Những câu hỏi của tôi:

  1. Phải exec 2>&1làm gì đây?
  2. Tại sao nó thất bại cho tôi?

Câu trả lời:


16

Kịch bản của bạn không bị lỗi - nó hoạt động tốt. Sự hiểu biết của bạn là chính xác trong đó exec >logfile; exec 2>&1chuyển hướng cả đầu ra tiêu chuẩn và lỗi tiêu chuẩn logfile. Vì vậy, bạn nên tìm kiếm trong tệp nhật ký chứ không phải thiết bị đầu cuối của bạn cho đầu ra và lỗi. Nếu bạn thực hiện các chuyển hướng đó trực tiếp trong vỏ hiện tại của mình, có vẻ như vỏ của bạn đã bị đóng băng vì bạn đã gửi tất cả đầu ra ra khỏi thiết bị đầu cuối của mình.

Lưu ý rằng đầu ra từ tùy chọn xtrace( set -x) cũng chuyển sang lỗi tiêu chuẩn, luôn là mô tả tệp 2 ... mà bạn đã gửi đi đến tệp nhật ký. Bạn nên tìm phần còn lại của nó sau khi exec 2>&1ở trong đó.


À, cảm ơn! Và nếu tôi mở một cửa sổ mới và thực hiện, tail -f /var/tmp/logfile.39918tôi sẽ thấy mọi thứ tôi gõ trong cửa sổ cũ. Khéo léo thông minh!
Stefan Lasiewski

1
"... gửi cả đầu ra tiêu chuẩn và đầu vào tiêu chuẩn tới logfile, ..." phải là "đầu ra tiêu chuẩn và lỗi tiêu chuẩn " . Tôi sẽ chỉnh sửa để chỉnh sửa.
Kevin Fegan

4

Hình thức thực thi này (tức là không có lệnh) được sử dụng để chuyển hướng tất cả đầu ra tiếp theo từ trình thông dịch shell hiện tại.

từ trợ giúp tích hợp của bash:

$ giúp thực thi
exec: exec [-cl] [-a name] [lệnh [argument ...]] [chuyển hướng ...]
    Thay vỏ bằng lệnh đã cho.

    Thực thi LỆNH, thay thế vỏ này bằng chương trình đã chỉ định.
    ARGUMENT trở thành đối số cho LỰA CHỌN. Nếu THÔNG TIN không được chỉ định,
    bất kỳ chuyển hướng có hiệu lực trong vỏ hiện tại.
    [...]

Tôi sử dụng exec &> logfile để chuyển hướng stdout và stderr cùng một lúc. ví dụ: hầu hết các tập lệnh bao bọc sao lưu và rsync của tôi (hoặc bất kỳ tập lệnh nào tạo ra nhiều đầu ra mà tôi có thể muốn kiểm tra chi tiết sau) bắt đầu bằng một cái gì đó như thế này:

BNAME=$(basename "$0" .sh)
LOGFILE="/tmp/$BNAME.log"
savelog "$LOGFILE"
exec &> "$LOGFILE"

Sau đó tôi chạy tập lệnh từ cron hoặc trong nền và sử dụng tail -Fđể xem logfile khi tập lệnh đang chạy. Savelog cho phép tôi giữ đầu ra từ 7 lần chạy cuối cùng (7 theo mặc định, savelog -ccó thể được sử dụng để thay đổi điều đó).


Câu hỏi đặc biệt nhắm vào vỏ Bourne. Bourne không có &>nhà điều hành, cũng không trích dẫn bashtrang người đàn ông rất hữu ích. Phần về cron là không liên quan.
jw013

Nó vẫn trả lời rõ ràng câu hỏi đầu tiên của anh ấy 'Điều hành 2> & 1 phải làm gì?' Mà thực sự chưa được trả lời. Giả sử một khả năng hợp lý để hiểu, khái quát hóa và ngoại suy không xứng đáng với -1. Tôi có xu hướng thích đưa ra một lời giải thích chung thay vì chỉ là phép thuật sùng bái hàng hóa cho một câu hỏi cụ thể. BTW, đó là trợ giúp bash, không phải trang bash man ... nó chỉ là tài liệu thuận tiện và ngắn gọn nhất, và điểm liên quan về việc có hiệu lực trong shell hiện tại áp dụng cho tất cả các phiên bản của sh.
cas

Tôi không thấy phần nào trong câu trả lời của bạn giải thích cụ thể điều gì exec 2>&1? Tôi thường hạ thấp các câu trả lời khuyến khích những quan niệm sai lầm, dù rõ ràng hay ngầm định (trong trường hợp của bạn, ngụ ý sh= bash), bởi vì không phải mọi người đọc câu trả lời của bạn trong tương lai sẽ biết sự khác biệt. bash dựa trên sh nhưng trong thực tế có nhiều điểm khác biệt (như &>: đưa nó vào tập lệnh shell Bourne có thể sẽ phá vỡ nó). Ngoài ra, không có tùy chọn nào bash execchấp nhận có khả năng hợp lệ.
jw013

Câu đầu tiên của tôi giải thích nó. Như câu cuối cùng trong bash giúp đầu ra. Phần còn lại là một ví dụ về lý do tại sao và làm thế nào một tính năng như vậy có thể được sử dụng - tại sao và làm thế nào thường được bỏ qua từ các trang man và tài liệu tham khảo khác.
cas

1
Q. "exec 2> & 1 phải làm gì?". A. "Hình thức thực thi này (tức là không có lệnh) được sử dụng để [...]". Không có sự nhầm lẫn giữa bash và sh trong câu đó. Nó đúng với tất cả các biến thể của sh. Bạn bỏ qua câu hỏi đầu tiên của anh ấy và trả lời câu hỏi thứ hai của anh ấy, tôi bỏ qua câu hỏi thứ hai của anh ấy và trả lời câu hỏi đầu tiên của anh ấy. Bạn đang đánh giá câu trả lời của tôi bằng câu hỏi bạn đã trả lời, không phải bởi câu tôi đã trả lời.
cas
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.