Привет мир, который обрабатывает ошибки

9

Напишите программу или функцию со следующими функциями:

  • Программа / функция сначала пытается записать строку Hello, world!в стандартный поток вывода. (Никакие другие формы вывода не являются приемлемыми для этой задачи, так как основное внимание уделяется вводу / выводу, а не тривиальному поведению самой программы.) В зависимости от того, удалось ли это:
    • Если вывод завершился успешно Hello, world!, программа / функция завершается без каких-либо дополнительных действий.
    • Если из-за ошибки не удалось получить правильный вывод, программа / функция пытается записать строку Error writing "Hello, world!"в стандартный поток ошибок. (Для этой задачи вам не нужна обработка ошибок для самой обработки ошибок.)

Разъяснения

  • Ваша программа / функция будет выполняться без ввода (если она не написана на языке, который абсолютно требует ввода для работы, и в этом случае она будет выполняться с максимально простым вводом).

  • При выводе вы также можете создать одиночный завершающий перевод строки, но это не обязательно.

  • Определение «ошибка записи в стандартный вывод», которое реализует ваша программа, должно обрабатывать как минимум следующие случаи как ошибки:

    • Стандартный вывод не существует (т. stdoutЕ. Является закрытым дескриптором файла, дескриптор файла 1 не существует, или, однако, эти случаи переводятся на язык и ОС, которые вы используете);
    • Стандартный вывод со ссылкой на файл на диске, на котором не осталось свободного места;
    • Стандартный выход подключается к другой программе, которая уже закрыла свой конец подключения.

    и должен относиться как минимум к следующим случаям как к успеху (т.е. не к ошибке):

    • Стандартный выход подключается к терминалу и Hello, world!отображается на экране.
    • Стандартный вывод подключается к файлу и Hello, world!записывается в файл.

    Вы можете выбрать детали того, что считается ошибкой вывода, если это соответствует приведенным выше правилам.

  • Ваша программа / функция не должна аварийно завершать работу при возникновении любой из перечисленных выше ошибок. Вам решать, какой код выхода вы используете.

  • Ваша программа / функция не должна описывать природу обнаруженной ошибки в стандартном потоке ошибок; он должен просто напечатать указанную выше строку. Посторонний вывод при стандартной ошибке (например, предупреждения компилятора) допустим только в том случае, если он генерируется безоговорочно, независимо от того, возникла ошибка или нет.

  • Ваша программа должна работать только в одной операционной системе (хотя это должна быть та, в которой ошибки, перечисленные выше, имеют смысл; я постарался сделать их достаточно общими, чтобы работать в большинстве многозадачных операционных систем, но странные операционные системы вполне могут быть исключен из этого вызова). Если ваша программа не переносима, перечислите предположения, необходимые для ее выполнения, в заголовке вашей заявки.

  • Эта задача может быть невозможна на всех языках (не каждый язык позволяет программе обрабатывать ошибки вывода по-своему). Вам нужно будет выбрать язык там, где это возможно.

  • Убедитесь, что ваша программа / функция работает! Не просто доверяйте документации библиотечных функций делать то, что они говорят, что делают. Обработка ошибок простых функций вывода часто оказывается на практике нарушенной, даже если функции утверждают, что они обрабатывают ошибки в теории.

Контрольные примеры

Вот способ смоделировать каждое из условий ошибки, описанных выше bashв Linux (вам не нужно использовать Linux, но, вероятно, это самая простая система для тестирования):

your_program_here >&-           # nonexistent stdout
your_program_here > /dev/full   # out of disk space
mkfifo test  # note: change "test" to a filename that isn't in use
true < test &
your_program_here > test        # connecting to a program that doesn't want input
rm test      # clean up the FIFO we used earlier

Первые два теста являются детерминированными. Последнее не (это зависит от состояния гонки); в целях тестирования я рекомендую добавить задержку между запуском вашей программы и фактическим выходом к стандартному выводу, чтобы гарантировать, что условие гонки разрешается таким образом, что это приводит к ошибке.

Состояние победы

Это вызов, тем короче, тем лучше. Как (почти) всегда, мы измеряем длину программы в байтах.


источник
1
Знаете ли вы, если есть способ проверить это на Windows? Я могу проверить первый критерий, но не часть о том, что диск заполнен ...
Стьюи Гриффин,
Чтобы уменьшить состояние гонки, вы могли бы использовать sleep 1 < test; (sleep 2; your_program_here) > test?
Нил

Ответы:

6

Баш , 71 60 байт

h=Hello,\ world!
(echo $h)2>&-||echo Error writing \"$h\">&2

Попробуйте онлайн!

Как это работает

После сохранения Hello, world!в переменную h мы делаем следующее.

Во-первых, (echo $h)2>&-попытки печати Hello, world!в STDOUT. 2>&-требуется для предотвращения отображения сообщения об ошибке echo: write error: неверный дескриптор файла в случае сбоя записи. Поскольку запись в именованный канал, который не принимает ввод, приведет к уничтожению программы Bash с сигналом 13 (SIGPIPE), мы выполним команду в subshell ( (...)), поэтому будет уничтожен только подоболочка.

Наконец, если печать в STDOUT не удалась, подоболочка завершится с ненулевым кодом состояния (141 для SIGPIPE, 1 для общей ошибки), поэтому echo Error writing \"$h\">&2печатает желаемое сообщение в STDERR.

Деннис
источник
1

Zsh , 55 байтов

h=Hello,\ world!
2>&-<<<$h||<<<'Error writing "'$h\">&2

В отличие от своей кузины Баш, Зш отказывается умирать из-за сломанной трубы.

Попробуйте онлайн!

Деннис
источник
1

C (gcc) , 87 86 байт

f(){signal(13,1);write(1-puts("Hello, world!"),"Error writing \"Hello, world!\"",29);}

Попробуйте онлайн!

Ungolfed

#include <signal.h>
#include <stdio.h>
#include <unistd.h>

void f(void)
{
    signal(SIGPIPE, SIG_IGN); // Works (and is required) on TIO. YMMV
    int fd = (puts("Hello, world!")) < 0 ? 2 : -13;
    write(fd, "Error writing \"Hello, world!\"", 29);
}
Деннис
источник
откуда вы знаете, что отдаёт? здесь говорится, что это> = 0, чтобы все было хорошо ...
RosLuP
putsвозвращает количество записанных байтов или -1 в случае ошибки, поэтому возвращает либо 14 (Hello World плюс перевод строки), либо -1 . (Это может зависеть от платформы, но именно так она себя ведет с glibc.)
Деннис
K & R2 говорит, что возвращает EOF [-1 практически] в случае ошибки; или значение не отрицательное, если все в порядке
RosLuP
1
В PPCG языки определяются их реализацией, а gcc / glibc ведет себя так, как я сказал.
Деннис
я предпочитаю старую книгу
РосЛюП
1

PowerShell, 80 байт

try{echo($h="Hello, World!") -ea 4}catch{$host.ui|% *rL* "Error writing ""$h"""}

пояснил:

try{
    #Attempt to 'echo' (write output) the string, and assign it to $h
    #Make sure the 'error action' is set to '4' to make it a terminating error.
    echo($h="Hello, World!") -ea 4
} catch { 
    #Use the "WriteErrorLine" function in $host.ui to stderr
    $host.ui|% *rL* "Error writing ""$h"""
}

не удалось на самом деле попробовать это, когда он ошибается, но это определенно ~ должно ~ работать.

colsw
источник
Сообщение об ошибке должно быть записано в STDERR . Запись в STDOUT невозможна, если во время первой попытки записи произошла ошибка.
Деннис
@ Денис спасибо за это, обновил там, не прочитал вопрос полностью.
colsw
Afaict PowerShell только ловит фатальные исключения, так что вам нужно Write-Host -ErrorAction Stopили что-то в этом роде. Кроме того, throwпроизводит дополнительную отладочную информацию помимо строки, которую она должна напечатать, которая, кстати, должна иметь строчную букву W и двойные кавычки вокруг строки HW.
Деннис
@Dennis дополнительная информация отладки сокрушила меня, ответ обновлен там теперь.
colsw
1

Javascript, 79 76 байт

try{(l=console).log(a="Hello, world!")}catch(e){l.error('Error writing '+a)}
Мэтью Ро
источник
Обратите внимание, что вы должны вывести строку 'Hello, world!', которая на один байт длиннее, чем вы используете. Кроме того, я полагаю, что назначение aвнутри вызова console.logбудет короче (1B) и удаление точки с запятой после l.log(a)сохранения другого байта.
Люк
@ Luke Спасибо, это была довольно большая ошибка!
Мэтью Ро
1
try{(l=console).log(a="Hello, world!")}catch(e){l.error('Error writing '+a)}для 76 байтов. Сначала consoleназначается l, затем "Hello, world!'назначается a, а затем выполняется.
Лука
0

Perl 5, 51 байт

требует -M5.01, что бесплатно

say$h="Hello, world!"or die"Error writing \"$h\"$/"

Протестировано в Strawberry Perl 5.24.0, запустив программу как есть (вывод на стандартный вывод) и запустив

print f $h="Hello, world!"or die"Error writing \"$h\"$/"

(напечатано со стандартной ошибкой). Я не знаю, как проверять другие ошибки, используя Strawberry, но они должны обрабатываться одинаково…

msh210
источник
Насколько я могу судить, это не работает. tio.run/nexus/bash#jY3NDoIwEITvfYq1IXCiiD83ys3Ei2/… (в строке также отсутствует запятая.)
Деннис
Я не знаю, что делать с той страницей, на которую вы ссылались; объясните пожалуйста? Также обратите внимание, что скрипт должен работать только на одной ОС. И я добавлю запятую; Спасибо.
msh210
Вывод должен отображаться Hello, world!после === 1 ===и ничего после остальных. Отладка не должна отображать ничего после === 1 ===и Error writing "Hello, world!"после остальных. Я знаю, что ваша программа не должна работать на TIO, но print f...показывает предполагаемые сообщения об ошибках, в то время как оригинальная программа этого не делает.
Деннис
«Вывод» и «Отладка», насколько я вижу, ничего не отображают. Я также не знаю, какими должны быть разделы «Верхний колонтитул» и «Нижний колонтитул». И я совершенно незнаком с TIO, но учтите, что Strawberry Perl работает на MS Windows.
msh210
Хет-данс Деннису за идею сохранения строки в переменной (хотя я, вероятно, подумал бы об этом, если бы не увидел ее там).
msh210
0

REXX, 111 106 байт

signal on notready
a='Hello, world!'
_=lineout(,a)
exit
notready:_=lineout('stderr','Error writing "'a'"')

Программа полагается на наличие потока с именем 'stderr'. Это, вероятно, не будет иметь место в системах IBM.

idrougge
источник
0

C 77 байт

f(a){a="Error writing \"Hello, world!\"";write(1,a+15,13)-13&&write(2,a,29);}

для вызова

main(){f(1); return 0;}
RosLuP
источник
На какой платформе вы это тестировали? Он не работает в Linux, если обнаружен сломанный канал.
Деннис
0

R , 91 байт

s="Hello, world!"
tryCatch(cat(s),error=function(e)cat('Error writing "','"',file=2,sep=s))

Попробуйте онлайн!

Я попытался ошибиться, запустив его cat(s,file=12)вместо cat(s), и он напечатал правильный текст в stderr. В invalid connectionпротивном случае это ошибка.

Jayce
источник
Любая идея, как проверить на другие ошибки вывода?
JayCe