echo mà đầu ra cho stderr


1116

Có một công cụ Bash tiêu chuẩn hoạt động như echo nhưng xuất ra stderr chứ không phải stdout?

Tôi biết tôi có thể làm echo foo 1>&2nhưng điều đó hơi xấu và, tôi nghi ngờ, dễ bị lỗi (ví dụ như nhiều khả năng bị chỉnh sửa sai khi mọi thứ thay đổi).


Câu trả lời:


1453

Bạn có thể làm điều này, tạo điều kiện cho việc đọc:

>&2 echo "error"

>&2sao chép mô tả tệp # 2 sang mô tả tệp # 1. Do đó, sau khi chuyển hướng này được thực hiện, cả hai bộ mô tả tệp sẽ tham chiếu đến cùng một tệp: mô tả một tệp # 2 ban đầu được đề cập đến. Để biết thêm thông tin, xem Hướng dẫn chuyển hướng minh họa Bash Hackers .


2
Tôi học được mẹo này khá lâu rồi. Trang này có một số thông tin tốt cho nó. tldp.org/LDP/abs/html/io-redirection.html
Marco Aurelio

46
@BCS Tôi không biết về việc sử dụng aliastập lệnh shell. Có lẽ sẽ an toàn hơn khi sử dụngerrcho(){ >&2 echo $@; }
Braden Best

3
> & 2 thường được đặt ở cuối. Điều này sẽ hoạt động, nhưng nó được sử dụng ít thường xuyên hơn
Iskren Ivov Chernev

159
Trong gần 40 năm tôi đã sử dụng các hệ thống giống Unix, tôi chưa bao giờ nghĩ rằng bạn có thể đặt chuyển hướng ở bất cứ đâu nhưng cuối cùng. Đặt nó lên phía trước như thế này làm cho nó rõ ràng hơn nhiều (hoặc "tạo điều kiện cho việc đọc" như @MarcoAurelio nói). +1 để dạy tôi một cái gì đó mới.
Hephaestus

FYI: nếu bạn muốn định dạng hoặc làm bất cứ điều gì ngoài việc đơn giản lặp lại chuỗi thì bạn sẽ phải chuyển hướng chuyển hướng về cuối. Ví dụ errcho(){ >&2 echo $@|pr -To5;}sẽ không hoạt động. Để làm điều gì đó tương tự, bạn sẽ phải đặt chuyển hướng ở đâu đó sau đường ống cuối cùng như:errcho(){ echo $@|>&2 pr -To5;}
Jon Red

423

Bạn có thể định nghĩa một hàm:

echoerr() { echo "$@" 1>&2; }
echoerr hello world

Điều này sẽ nhanh hơn một kịch bản và không có phụ thuộc.

Gợi ý cụ thể về bash của Camilo Martin sử dụng "chuỗi ở đây" và sẽ in bất cứ thứ gì bạn chuyển đến nó, bao gồm cả các đối số (-n) mà tiếng vang thường sẽ nuốt:

echoerr() { cat <<< "$@" 1>&2; }

Giải pháp của Glenn Jackman cũng tránh được vấn đề nuốt phải tranh luận:

echoerr() { printf "%s\n" "$*" >&2; }

7
Tôi phải nói rằng tiếng vang là không đáng tin cậy. echoerr -ne xtsẽ không in "-ne xt". Sử dụng tốt hơn printfcho điều đó.
Camilo Martin

10
Ồ, bạn cũng thực sự có thể sử dụng mèo:echoerr() { cat <<< "$@" 1>&2; }
Camilo Martin

2
Tôi đã không nhận thức được điều đó. Thêm.
James Roth

4
Hoặc,printf "%s\n" "$*" >&2
glenn jackman

4
@GKFX Tất nhiên nó chỉ hoạt động chính xác khi trích dẫn. Tại sao mọi người không trích dẫn chuỗi của họ là ngoài tôi. (khi bạn không trích dẫn, mọi thứ ngăn cách bởi một hoặc nhiều $IFSkhoảng trắng được gửi như một lý lẽ riêng, mà trong trường hợp echophương tiện concatenating chúng với 0x20s, nhưng sự nguy hiểm của không trích dẫn xa outweight sự tiện lợi của 2 nhân vật ít hơn để gõ) .
Camilo Martin

252

1là đầu ra tiêu chuẩn, bạn không cần phải đặt tên rõ ràng trước một chuyển hướng đầu ra như thế >mà thay vào đó có thể chỉ cần gõ:

echo Thông báo này đi tới stderr> & 2

Vì bạn có vẻ lo lắng rằng 1>&2bạn sẽ khó có thể gõ một cách đáng tin cậy, nên việc loại bỏ dư thừa 1có thể là một sự khích lệ nhỏ đối với bạn!


59

Một lựa chọn khác

echo foo >>/dev/stderr

4
Là tùy chọn này di động? Có ai biết nếu điều này không làm việc cho một số hương vị unix?
Dacav

7
Nó không hoạt động trong một số chroots nhất định, không thể truy cập / dev / stderr.
Zachary Vance

12
Nếu tập lệnh thực thi dòng này - hãy gọi nó foo- có chuyển hướng stderr của riêng nó - ví dụ foo >foo.log 2>&1- sau đó echo foo >/dev/stderrsẽ ghi đè tất cả đầu ra trước nó. >>nên được sử dụng thay thế:echo foo >>/dev/stderr
doshea

Tương tự, bạn có /dev/fd/2.
jbruni

@Dacav cái này chắc chắn xách tay : /proc/self/fd/2. Xem câu trả lời của tôi dưới đây :)
Sebastian

31

Không, đó là cách tiêu chuẩn để làm điều đó. Nó không gây ra lỗi.


9
không gây ra lỗi, nhưng tôi có thể có nhiều khả năng hơn. OTOH nó không phải là một vấn đề lớn.
BCS

6
@Mike DeSimone: Nếu người khác làm hỏng mã, xáo trộn xung quanh đầu ra và không thực sự biết bash, họ có thể dễ dàng bỏ (hoặc gõ nhầm) 1>&2. Tất cả chúng ta đều mong muốn điều này sẽ không xảy ra, nhưng tôi chắc chắn rằng tất cả chúng ta đều là những nơi nó xảy ra.
Cascabel

2
( echo something 1>&2 ; something else ) > log-> (echo something; cp some junk 1>&2 ; something else) > logRất tiếc.
BCS

29
IMHO, nếu ai đó nhắn tin vào mã và không biết bash, đây có thể là vấn đề nhỏ nhất của bạn.
Mike DeSimone

7
Tôi nghĩ rằng nếu đó có thể là một vấn đề, bạn nên bắt đầu sử dụng một ngôn ngữ khác: cố gắng làm cho bash trở nên hoàn hảo là một trò mạo hiểm.
trực giác

17

Nếu bạn không nhớ đăng nhập tin nhắn vào syslog, cách not_so_ugly là:

logger -s $msg

Tùy chọn -s có nghĩa là: "Xuất thông báo thành lỗi tiêu chuẩn cũng như nhật ký hệ thống."


1
điều đó thật tuyệt! nó di động thế nào
code_monk

@code_monk: Lệnh logger dự kiến ​​sẽ tương thích với IEEE Std 1003.2 ("POSIX.2"), Lệnh logger là một phần của gói produc-linux và có sẵn từ Linux Kernel Archive kernel.org/pub/linux/utils / produc-linux .
miku

12

Đây là một hàm STDERR đơn giản, giúp chuyển hướng đầu vào đường ống thành STDERR.

#!/bin/bash
# *************************************************************
# This function redirect the pipe input to STDERR.
#
# @param stream
# @return string
#
function STDERR () {

cat - 1>&2

}

# remove the directory /bubu
if rm /bubu 2>/dev/null; then
    echo "Bubu is gone."
else
    echo "Has anyone seen Bubu?" | STDERR
fi


# run the bubu.sh and redirect you output
tux@earth:~$ ./bubu.sh >/tmp/bubu.log 2>/tmp/bubu.err

2
Tôi nghĩ bạn có thể làm điều tương tự với bí danh và gọn hơn nhiều
BCS

hoặc bạn chỉ có thể chuyển trực tiếp đến tập tin thiết bị echo what | /dev/stderr...
ardew

11

Lưu ý: Tôi đang trả lời bài đăng - không phải câu hỏi "tiếng vang" mơ hồ / đầu ra cho thiết bị lỗi chuẩn (đã được OP trả lời).

Sử dụng một chức năng để hiển thị ý định và nguồn thực hiện bạn muốn. Ví dụ

#!/bin/bash

[ -x error_handling ] && . error_handling

filename="foobar.txt"
config_error $filename "invalid value!"

output_xml_error "No such account"

debug_output "Skipping cache"

log_error "Timeout downloading archive"

notify_admin "Out of disk space!"

fatal "failed to open logger!"

error_handlingđược:

ADMIN_EMAIL=root@localhost

config_error() { filename="$1"; shift; echo "Config error in $filename: $*" 2>&1; }

output_xml_error() { echo "<error>$*</error>" 2>&1; }

debug_output() { [ "$DEBUG"=="1" ] && echo "DEBUG: $*"; }

log_error() { logger -s "$*"; }

fatal() { which logger >/dev/null && logger -s "FATAL: $*" || echo "FATAL: $*"; exit 100; }

notify_admin() { echo "$*" | mail -s "Error from script" "$ADMIN_EMAIL"; }

Những lý do xử lý mối quan tâm trong OP:

  • cú pháp đẹp nhất có thể (từ có nghĩa thay vì biểu tượng xấu xí)
  • khó mắc lỗi hơn (đặc biệt nếu bạn sử dụng lại tập lệnh)
  • nó không phải là một công cụ Bash tiêu chuẩn, nhưng nó có thể là một thư viện shell tiêu chuẩn cho bạn hoặc công ty / tổ chức của bạn

Những lý do khác:

  • sự rõ ràng - thể hiện ý định với những người bảo trì khác
  • tốc độ - chức năng nhanh hơn shell script
  • tái sử dụng - một chức năng có thể gọi một chức năng khác
  • cấu hình - không cần chỉnh sửa tập lệnh gốc
  • gỡ lỗi - dễ dàng hơn để tìm dòng chịu trách nhiệm cho lỗi (đặc biệt là nếu bạn đang xử lý lỗi với hàng tấn đầu ra chuyển hướng / lọc)
  • mạnh mẽ - nếu một chức năng bị thiếu và bạn không thể chỉnh sửa tập lệnh, bạn có thể quay lại sử dụng công cụ bên ngoài có cùng tên (ví dụ: log_error có thể được đặt bí danh cho logger trên Linux)
  • chuyển đổi triển khai - bạn có thể chuyển sang các công cụ bên ngoài bằng cách xóa thuộc tính "x" của thư viện
  • bất khả tri đầu ra - bạn không còn phải quan tâm nếu nó đi đến STDERR hoặc nơi khác
  • cá nhân hóa - bạn có thể định cấu hình hành vi với các biến môi trường

10

Đề xuất của tôi:

echo "my errz" >> /proc/self/fd/2

hoặc là

echo "my errz" >> /dev/stderr

echo "my errz" > /proc/self/fd/2sẽ hiệu quả đầu ra stderr/proc/selflà một liên kết đến các quá trình hiện tại, và /proc/self/fdgiữ quá trình mở file descriptor, và sau đó, 0, 1, và 2đại diện cho stdin, stdoutstderrtương ứng.

Các /proc/selfliên kết không hoạt động trên hệ điều hành MacOS, tuy nhiên, /proc/self/fd/*hiện có sẵn trên Termux trên Android, nhưng không phải /dev/stderr. Làm thế nào để phát hiện HĐH từ tập lệnh Bash? có thể giúp đỡ nếu bạn cần làm cho tập lệnh của mình dễ di chuyển hơn bằng cách xác định biến thể nào sẽ sử dụng.


5
Các /proc/selfliên kết không hoạt động trên hệ điều hành MacOS, vì vậy tôi sẽ gắn bó với các chi tiết thẳng về phía trước /dev/stderrphương pháp. Ngoài ra, như đã lưu ý trong các câu trả lời / nhận xét khác, có lẽ tốt hơn là sử dụng >>để chắp thêm.
MarkHu

4
/proc/self/fd/*có sẵn trên Termux trên Android, nhưng không /dev/stderr.
go2null

9

Đừng sử dụng catnhư một số được đề cập ở đây. catlà một chương trình trong khi echoprintflà các nội trang bash (shell). Khởi chạy một chương trình hoặc một tập lệnh khác (cũng được đề cập ở trên) có nghĩa là tạo ra một quy trình mới với tất cả chi phí. Sử dụng các nội trang, các hàm viết khá rẻ, vì không cần phải tạo (thực thi) một quy trình (môi trường).

Các opner hỏi "có công cụ tiêu chuẩn nào để xuất ( ống ) thành stderr không", câu trả lời schort là: KHÔNG ... tại sao? ... ống dẫn rediredcting là một khái niệm ưu tú trong các hệ thống như unix (Linux ...) và bash (sh) xây dựng trên các khái niệm này.

Tôi đồng ý với người mở rằng chuyển hướng với các ký hiệu như thế này: &2>1không dễ chịu cho các lập trình viên hiện đại, nhưng đó là bash. Bash không có ý định viết các chương trình lớn và mạnh mẽ, nó nhằm mục đích giúp các quản trị viên đến đó làm việc với ít phím bấm hơn ;-)

Và ít nhất, bạn có thể đặt chuyển hướng bất cứ nơi nào trong dòng:

$ echo This message >&2 goes to stderr 
This message goes to stderr

1
Nói các nhà phát triển không sử dụng các chương trình chỉ vì lý do hiệu suất là tối ưu hóa sớm. Các cách tiếp cận thanh lịch, dễ thực hiện nên được ưu tiên hơn các mã khó hiểu, hoạt động tốt hơn (theo thứ tự mili giây).
GuyPaddock

@GuyPaddock xin lỗi, bạn chưa đọc đúng điều này. Linh sam; Đó là về chuyển hướng đường ống được xử lý tốt bởi bash. Nếu một người không thích cú pháp (xấu xí) cách bash chuyển hướng, anh ta nên ngừng thực hiện các tập lệnh bash hoặc tìm hiểu cách bash. Thứ hai; bạn nên biết rằng việc tung ra một prozess mới tốn kém như thế nào so với việc gọi một bash dựng sẵn.
trở về42

1
Có một sự khác biệt giữa việc cho ai đó biết sự đánh đổi hiệu năng của Bash dựng sẵn so với catvà hướng dẫn ai đó không sử dụng mèo vì nó chậm. Có vô số trường hợp sử dụng trong đó mèo là lựa chọn đúng đắn, vì vậy đó là lý do tại sao tôi phản đối câu trả lời của bạn.
GuyPaddock

@GuyPaddock Người mở yêu cầu echothay thế. Ngay cả khi anh ta sử dụng cat, anh ta phải sử dụng chuyển hướng bash. dù sao. Vì vậy, hoàn toàn không có ý nghĩa để sử dụng catở đây. BTW Tôi sử dụng cat100 lần một ngày, nhưng không bao giờ trong bối cảnh người mở yêu cầu ... bạn hiểu chứ?
return42

8

Một lựa chọn khác mà tôi gần đây vấp phải là:

    {
        echo "First error line"
        echo "Second error line"
        echo "Third error line"
    } >&2

Điều này chỉ sử dụng các hàm dựng sẵn của Bash trong khi làm cho đầu ra lỗi nhiều dòng ít bị lỗi hơn (vì bạn không phải nhớ thêm &>2vào mỗi dòng).


1
Không thể tin được, bạn bỏ phiếu cho tôi khi tôi khuyên bạn nên sử dụng bash-redirect và trong câu trả lời của riêng bạn, bạn đang sử dụng bash-redirect.
return42

1
@ return42 Tôi đã bỏ phiếu cho câu trả lời của bạn vì tất cả những gì đã làm là nói với OP rằng không có câu trả lời nào tốt hơn những gì họ bắt đầu .. đó không thực sự là một câu trả lời. Tôi cũng không thấy đề xuất vỏ phụ trong câu trả lời của bạn ... câu trả lời của bạn thực sự chỉ khuyên OP không nên sử dụng cathoặc bất kỳ tiện ích nào khác, không có chủ đề cho câu hỏi.
GuyPaddock


6

read là một lệnh dựng sẵn shell in ra stderr và có thể được sử dụng như echo mà không cần thực hiện các thủ thuật chuyển hướng:

read -t 0.1 -p "This will be sent to stderr"

Thời -t 0.1gian chờ là vô hiệu hóa chức năng chính của đọc, lưu trữ một dòng stdin vào một biến.


5
Bash trên OS X không cho phép "0.1"
James Roth

2

Tạo kịch bản

#!/bin/sh
echo $* 1>&2

đó sẽ là công cụ của bạn

Hoặc tạo một chức năng nếu bạn không muốn có một tập lệnh trong tệp riêng biệt.


6
Tốt hơn là nó là một chức năng (như câu trả lời của James Roth), và tốt hơn là vượt qua tất cả các đối số, không chỉ là đầu tiên.
Cascabel

2
Tại sao một chức năng sẽ tốt hơn? (Hoặc, thay vào đó: "Tốt hơn để giải thích lý do tại sao nó sẽ tốt hơn ...")
Ogre Psalm33

3
@ OgrePsalm33 Một lý do một chức năng sẽ tốt hơn là khi gọi một tập lệnh, thông thường một thể hiện shell mới được tạo để cung cấp một môi trường để thực thi tập lệnh. Mặt khác, một chức năng được đặt vào môi trường của shell hiện đang chạy. Gọi một hàm, trong trường hợp này, sẽ là một hoạt động hiệu quả hơn nhiều vì việc tạo ra một thể hiện khác của shell sẽ tránh được.
Destenson

-10

Mac OS X: Tôi đã thử câu trả lời được chấp nhận và một vài câu trả lời khác và tất cả chúng đều dẫn đến việc viết STDOUT không STDERR trên máy Mac của tôi.

Đây là một cách di động để ghi vào lỗi tiêu chuẩn bằng Perl:

echo WARNING! | perl -ne 'print STDERR'

lol downvote tất cả những gì bạn muốn nhưng đây là giải pháp tôi thực sự sử dụng trong mã của mình!
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.