відлуння, яке виводиться на більш жорсткий


1115

Чи є стандартний інструмент Bash, який діє як ехо, але виводить на stderr, а не stdout?

Я знаю, що можу зробити, echo foo 1>&2але це якось некрасиво і, я підозрюю, схильний до помилок (наприклад, більше шансів змінити неправильно, коли зміниться ситуація).


Відповіді:


1452

Ви можете це зробити, що полегшує читання:

>&2 echo "error"

>&2копіює дескриптор файлу №2 у дескриптор файлу №1. Отже, після цього перенаправлення обидва дескриптори файлів будуть посилатися на один і той же файл: один дескриптор файлу №2 спочатку посилався . Для отримання додаткової інформації дивіться посібник з перенаправлення ілюстрованих хакерів Bash .


2
Цю хитрість я дізнаюся досить давно. На цій сторінці є хороша інформація. tldp.org/LDP/abs/html/io-redirection.html
Marco Aurelio

46
@BCS Я не хочу використовувати aliasсценарій оболонки. Це, мабуть, було б безпечнішеerrcho(){ >&2 echo $@; }
Braden Best

3
> & 2 зазвичай ставиться в кінці. Це спрацює, але його використовують рідше
Іскрен Івов Чернев

159
За майже 40 років, що я використовую системи, схожі на Unix, мені ніколи не спадало на думку, що ви можете поставити переспрямування куди завгодно, але в кінці. Якщо поставити його на передній план так, це стає набагато очевиднішим (або "полегшує читання", як говорить @MarcoAurelio). +1 для того, щоб навчити мене чомусь новому.
Гефест

FYI: якщо ви хочете відформатувати або зробити що-небудь, окрім просто перегукувати рядок, вам доведеться перенести переадресацію назад до кінця. Наприклад errcho(){ >&2 echo $@|pr -To5;}, не буде працювати. Щоб зробити щось подібне, вам доведеться поставити переспрямування кудись після останньої труби на зразок:errcho(){ echo $@|>&2 pr -To5;}
Джон Ред

423

Ви можете визначити функцію:

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

Це було б швидше, ніж сценарій і не матиме залежностей.

У конкретному базі Каміло Мартіна використовується рядок "тут" і буде надруковано все, що ви передаєте до нього, включаючи аргументи (-n), які зазвичай лунають відлунням:

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

Рішення Глена Джекмана також уникає проблеми проковтування аргументів:

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

7
Треба сказати, що відлуння якось недостовірне. echoerr -ne xtне збирається друкувати "-ne xt". Краще використовувати printfдля цього.
Каміло Мартін

10
О, ви також можете використовувати кішку також:echoerr() { cat <<< "$@" 1>&2; }
Каміло Мартін,

2
Я цього не знав. Додано.
Джеймс Рот

4
Або,printf "%s\n" "$*" >&2
glenn jackman

4
@GKFX Звичайно, він працює правильно лише при цитуванні. Чому люди не цитують своїх рядків - це поза мене. (якщо ви не цитуєте, все, розділене однією чи кількома $IFSпробілами, надсилається як окремий аргумент, що у випадку echoозначає, що вони об'єднують їх із 0x20s, але небезпека не навести набагато більшу вагу зручності 2 менших символів набрати) .
Каміло Мартін

252

Оскільки 1це стандартний вихід, вам не потрібно чітко називати його перед перенаправленням виводу, як, >а натомість можна просто ввести:

echo Це повідомлення переходить до stderr> & 2

Оскільки ви, мабуть, переживаєте, що вам 1>&2буде важко надійно набрати, усунення зайвого 1може стати для вас незначним заохоченням!


59

Ще один варіант

echo foo >>/dev/stderr

4
Цей варіант портативний? Хтось знає, чи це не працює на якийсь аромат Unix?
Дачав

7
Він не працює в певних хротах, які не можуть отримати доступ / dev / stderr.
Захарій Венс

12
Якщо сценарій, який виконує цей рядок - назвемо його, foo- має перенаправлений власний stderr - наприклад, foo >foo.log 2>&1- тоді echo foo >/dev/stderrбуде обмежено весь вихід перед ним. >>слід використовувати замість цього:echo foo >>/dev/stderr
doshea

Так само і у вас /dev/fd/2.
jbruni

@Dacav це напевно портативний: /proc/self/fd/2. Дивіться мою відповідь нижче :)
Себастьян

31

Ні, це стандартний спосіб зробити це. Це не повинно викликати помилок.


9
Це не повинно спричиняти помилок, але я, мабуть, частіше. ОТО це не така вже й велика справа.
BCS

6
@Mike DeSimone: Якщо хтось інший поспішає з кодом, перетасовується навколо виводу, і насправді не знає баш, він може легко скинути (або ввести помилку) 1>&2. Ми всі бажаємо, щоб цього не сталося, але я впевнений, що ми всі були там, де це робиться.
Каскабель

2
( echo something 1>&2 ; something else ) > log-> (echo something; cp some junk 1>&2 ; something else) > logНа жаль
BCS

29
ІМХО, якщо хтось псує код і не знає баш, це може бути найменшою вашою проблемою.
Майк Десімоне

7
Я думаю, якщо це, мабуть, буде проблемою, ви повинні почати використовувати іншу мову: намагатися зробити bash дурним - це задумка дурня.
інтуїтивно,

17

Якщо ви не заперечуєте за тим, щоб записати повідомлення також у syslog, спосіб not_so_ugly такий:

logger -s $msg

Параметр -s означає: "Виведіть повідомлення на стандартну помилку, а також на системний журнал."


1
це чудово! наскільки це портативно?
code_monk

@code_monk: Команда реєстратор , як очікується , буде IEEE Std 1003.2 ( «POSIX.2») сумісний, команда реєстратор є частиною пакета Util-Linux і доступний з Linux Kernel Архіву ⟨ kernel.org/pub/linux/utils / util- linux⟩.
міку

12

Це проста функція STDERR, яка перенаправляє вхід труби на 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
Я думаю, ви можете зробити те ж саме з псевдонімом і бути набагато компактнішим
BCS

або ви можете просто передати файл пристрою безпосередньо echo what | /dev/stderr...
ardnew

11

Примітка: я відповідаю на пост, а не на оманливе / розпливчасте "відлуння, яке призводить до більш жорсткого" питання (вже відповів ОП).

Використовуйте функцію, щоб показати наміри та джерело потрібної реалізації. Напр

#!/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будучи:

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"; }

Причини вирішення проблем в ОП:

  • можливий симпатичний синтаксис (значущі слова замість потворних символів)
  • важче зробити помилку (особливо якщо повторно використовувати сценарій)
  • це не стандартний інструмент Bash, але він може бути стандартною бібліотекою оболонок для вас або вашої компанії / організації

Інші причини:

  • ясність - показує наміри перед іншими обслуговуючими особами
  • speed - функції швидше, ніж сценарії оболонки
  • повторне використання - функція може викликати іншу функцію
  • конфігурація - не потрібно редагувати оригінальний сценарій
  • налагодження - простіше знайти рядок, що відповідає за помилку (особливо, якщо ви зупиняєтесь з тоною виходу переадресації / фільтрації)
  • надійність - якщо функція відсутня, і ви не можете редагувати сценарій, ви можете перейти до використання зовнішнього інструменту з тим самим іменем (наприклад, log_error можна подати до реєстрації в Linux)
  • переключення реалізацій - ви можете перейти до зовнішніх інструментів, видаливши атрибут "x" бібліотеки
  • вихідний агностик - вам більше не доведеться дбати, переходить він до STDERR або деінде
  • персоналізація - ви можете налаштувати поведінку за допомогою змінних оточення

10

Моя пропозиція:

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

або

echo "my errz" >> /dev/stderr

echo "my errz" > /proc/self/fd/2буде ефективно виводиться stderrтому , що /proc/selfце посилання на поточний процес, і /proc/self/fdтримає процес відкритий дескрипторів файлів, а потім 0, 1і 2стояти stdin, stdoutі stderrвідповідно.

/proc/selfПосилання не працює на MacOS, проте, /proc/self/fd/*є на Termux на Android, але не /dev/stderr. Як виявити ОС за сценарієм Bash? може допомогти, якщо вам потрібно зробити свій скрипт більш портативним, визначивши, який варіант використовувати.


5
/proc/selfПосилання не працює на MacOS, так що я буду дотримуватися більш прямолінійний /dev/stderrметод. Також, як зазначено в інших відповідях / коментарях, можливо, краще використовувати >>для додавання.
MarkHu

4
/proc/self/fd/*доступна в Termux на Android, але ні /dev/stderr.
go2null

9

Не використовуйте, catяк тут згадуються деякі. catє програмою в той час як echoі printfє bash (shell) вбудованими. Запуск програми або іншого сценарію (також згаданого вище) означає створити новий процес з усіма витратами. Використання вбудованих функцій запису є досить дешевим, оскільки немає необхідності створювати (виконувати) процес (-оточення).

Опнер запитує "чи є якийсь стандартний інструмент для виведення ( труби ) на stderr", відповідь Щорта: НІ ... чому? ... перенаправлення труб - це елементарна концепція в таких системах, як unix (Linux ...), і bash (sh) будується на цих концепціях.

Я погоджуюся з відкривачем, що перенаправлення з такими позначеннями: &2>1 не дуже приємна для сучасних програмістів, але це бажання. Баш не мав на меті писати величезні та надійні програми, він покликаний допомогти адміністраторам налагодити роботу з меншим натисканням клавіш ;-)

І принаймні, ви можете розмістити перенаправлення будь-де в рядку:

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

1
Сказати розробникам не використовувати програми лише з причини продуктивності - це передчасна оптимізація. Елегантний, простий у дотриманні підхід слід віддати перевагу перед важко зрозумілим кодом, який працює краще (порядку мілісекунд).
GuyPaddock

@GuyPaddock Вибачте, ви не правильно прочитали це. Ялиці; Йдеться про перенаправлення труб, з якими добре справляється баш. Якщо комусь не подобається (потворний) синтаксис, як перенаправляє bash, він повинен припинити реалізацію скриптів bash або вивчити спосіб bash. Другий; ви повинні знати, як дорого коштувати запуск нового прозеса порівняно з тим, що ви називаєте баш вбудований.
повернення42

1
Існує різниця між тим, щоб повідомити комусь про компроміси у вбудованих версіях Bash vs catі наказувати комусь не користуватися котом, оскільки це повільно. Існує незліченна кількість випадків використання, коли кіт - це правильний вибір, тому я заперечую проти вашої відповіді.
GuyPaddock

@GuyPaddock Відкривач попросив echoзаміну. Навіть якщо він використовує cat, він повинен використовувати перенаправлення bash. все одно. Отже, тут немає сенсу використовувати cat. До речі, я використовую cat100 разів на день, але ніколи в контексті відкривача не просив ... ти це отримав?
повернення42

8

Ще один варіант, про який я нещодавно натрапив:

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

Для цього використовуються лише вбудовані файли Bash, роблячи виведення багато рядкових помилок менш сприйнятливим до помилок (оскільки вам не потрібно пам'ятати, щоб додавати &>2до кожного рядка).


1
Не можете повірити, ви голосуєте мені, коли я рекомендую використовувати bash-redirect, а у власній відповіді ви використовуєте bash-redirect.
повернення42

1
@ return42 Я проголосував вашу відповідь, тому що все, що вона робила, було сказати ОП, що немає кращої відповіді, ніж те, з чого вони почали .. Це насправді не відповідь. У вашій відповіді я також не бачу пропозиції підрозділу. Ваша відповідь дійсно просто радить ОП не використовувати catчи будь-яку іншу утиліту, що не відповідає темі.
GuyPaddock


6

read - команда, побудована в оболонку, яка друкує на stderr, і може використовуватися як ехо, не виконуючи прийомів перенаправлення:

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

Це -t 0.1час, який вимикає основну функціональність читання, зберігаючи один рядок stdin у змінній.


5
Bash на OS X не дозволяє "0,1"
Джеймс Рот

2

Складіть сценарій

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

це був би ваш інструмент.

Або зробіть функцію, якщо ви не хочете мати сценарій в окремому файлі.


6
Краще, щоб це було функцією (на зразок відповіді Джеймса Рота), і краще передавати всі аргументи, не лише перші.
Каскабель

2
Чому функція була б кращою? (Або, як варіант: "Краще пояснити, чому було б краще ...")
Псалом Огре 3333

3
@ OgrePsalm33 Однією з причин того, що функція буде кращою, є те, що при виклику скрипту зазвичай створюється новий екземпляр оболонки, щоб забезпечити середовище для виконання сценарію. Функція, з іншого боку, розміщена в поточному середовищі оболонки, що працює. Виклик функції в цьому випадку було б набагато ефективнішою операцією, оскільки уникнути створення іншого екземпляра оболонки.
Дестенсон

-10

Mac OS X: Я спробував прийняту відповідь та пару інших відповідей, і всі вони призвели до написання STDOUT not STDERR на моєму Mac.

Ось портативний спосіб запису до стандартної помилки за допомогою Perl:

echo WARNING! | perl -ne 'print STDERR'

lol downvote все, що ви хочете, але це рішення, яке я фактично використовую в своєму коді!
Ной Суссман
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.