2010-06-28 38 views
34

Tôi đang viết một kịch bản để sao lưu cơ sở dữ liệu. Tôi có dòng sau:Bash script - lưu trữ stderr trong một biến

mysqldump --user=$dbuser --password=$dbpswd \ 
    --host=$host $mysqldb | gzip > $filename 

Tôi muốn gán stderr cho biến, để nó tự gửi email cho tôi biết điều gì đã xảy ra nếu xảy ra sự cố. Tôi đã tìm thấy các giải pháp để chuyển hướng stderr đến stdout, nhưng tôi không thể làm điều đó như stdout đã được gửi (thông qua gzip) vào một tệp. Làm thế nào tôi có thể lưu trữ riêng stderr trong một kết quả $ biến?

Trả lời

57

Hãy thử chuyển hướng stderr sang stdout và sử dụng $() để nắm bắt điều đó. Nói cách khác:

VAR=$((your-command-including-redirect) 2>&1) 

Vì lệnh của bạn chuyển hướng stdout ở đâu đó, nó không được can thiệp vào stderr. Có thể có một cách sạch hơn để viết nó, nhưng điều đó sẽ làm việc.

Edit:

Điều này thực sự làm việc. Tôi đã thử nghiệm nó:

#!/bin/bash                                           
BLAH=$((
(
echo out >&1 
echo err >&2 
) 1>log 
) 2>&1) 

echo "BLAH=$BLAH" 

sẽ in và BLAH=err file log chứa out.

+0

Tôi không nghĩ rằng nó hoạt động. stderr được chuyển hướng đến stdout, sau đó được chuyển hướng đến một tệp. Bạn không thể chuyển hướng lệnh stdout của lệnh đến một tệp và sau đó thay thế stdout được hiển thị bằng stderr –

+0

@Michael: Xem bản chỉnh sửa của tôi. –

+0

Hoạt động hoàn hảo. Cảm ơn! – thornate

0

dd viết cả stdout và stderr:

$ dd if=/dev/zero count=50 > /dev/null 
50+0 records in 
50+0 records out 

hai con suối là độc lập và redirectable riêng:

$ dd if=/dev/zero count=50 2> countfile | wc -c 
25600 
$ cat countfile 
50+0 records in 
50+0 records out 
$ mail -s "countfile for you" thornate < countfile 

nếu bạn thực sự cần một biến:

$ variable=`cat countfile` 
4

Bạn có thể lưu tham chiếu stdout từ trước khi nó được chuyển hướng trong một f khác số ile (ví dụ: 3) và sau đó chuyển hướng stderr đó:

result=$(mysqldump --user=$dbuser --password=$dbpswd \ 
    --host=$host $mysqldb 3>&1 2>&3 | gzip > $filename) 

Vì vậy 3>&1 sẽ chuyển hướng tập số 3 đến stdout (chú ý đây là trước khi stdout được chuyển hướng với các đường ống). Sau đó, 2>&3 chuyển hướng stderr đến tệp số 3, hiện giờ giống với tệp stdout. Cuối cùng stdout được chuyển hướng bằng cách được đưa vào một đường ống, nhưng điều này không ảnh hưởng đến số tệp 2 và 3 (thông báo rằng chuyển hướng stdout từ gzip không liên quan đến kết quả đầu ra từ lệnh mysqldump).

Chỉnh sửa: Đã cập nhật lệnh để chuyển hướng stderr từ lệnh mysqldump và không phải gzip, tôi đã quá nhanh trong câu trả lời đầu tiên của tôi.

8

Đối với bất kỳ lệnh chung chung trong Bash, bạn có thể làm một cái gì đó như thế này:

{ error=$(command 2>&1 1>&$out); } {out}>&1 

đầu ra thường xuyên xuất hiện bình thường, bất cứ điều gì để stderr được chụp trong $ lỗi (quote nó như "$ error" khi sử dụng nó để giữ lại dòng mới).Để chụp stdout vào một tập tin, chỉ cần thêm một chuyển hướng ở cuối, ví dụ:

{ error=$(ls /etc/passwd /etc/bad 2>&1 1>&$out); } {out}>&1 >output 

Breaking nó xuống, đọc từ bên ngoài vào, nó:

  • tạo ra một mô tả tập tin $ ra cho toàn bộ khối, sao chép stdout
  • nắm bắt giá trị của toàn bộ lệnh bằng lỗi $ (nhưng xem bên dưới)
  • lệnh tự chuyển hướng stderr sang giá trị stdout (được bắt ở trên), sau đó chuyển thành stdout gốc từ bên ngoài khối , do đó chỉ có stderr mới được captu màu đỏ
+1

Không hoạt động trong bash v3.2: '' token không mong muốn '{out} '' '. Cú pháp này có cần Bash 4 không? –

+0

nó hoạt động tốt trong bash 4.2 và 4.1, thậm chí tôi đã thử các cửa hàng: compat32, compat31 và nó cũng hoạt động tốt, có thể đó là lỗi trong 3.2 kể từ khi bash ở chế độ tương thích, trừ khi tính tương thích chỉ bao gồm các mục mà sẽ phá vỡ không phải do 4,2, không phải là các tính năng mà sẽ là một phần của 4.2 ... (tôi nghĩ rằng hầu hết mọi người sử dụng 4.2 những ngày này phải không?) Dù sao đây là một bài cũ nhưng chỉ để xóa nó ra, nó hoạt động và chỉ là những gì tôi cần để gán lỗi cho biến trong khi hiển thị văn bản bình thường trên màn hình ... :) – osirisgothra

Các vấn đề liên quan