Witaj świecie, który obsługuje błędy


9

Napisz program lub funkcję o następującej funkcjonalności:

  • Program / funkcja najpierw próbuje zapisać ciąg Hello, world!do standardowego strumienia wyjściowego. (Żadne inne formy wyników nie są akceptowalne dla tego wyzwania, ponieważ nacisk kładziony jest raczej na operacje we / wy, a nie na trywialne zachowanie samego programu.) W zależności od tego, czy się udało:
    • Jeśli zakończy się powodzeniem Hello, world!, program / funkcja kończy działanie bez dalszego działania.
    • Jeśli nie udało się wygenerować poprawnego wyniku z powodu błędu, program / funkcja próbuje zapisać ciąg znaków Error writing "Hello, world!"do standardowego strumienia błędów. (Na potrzeby tego wyzwania nie jest wymagana obsługa błędów dla samej obsługi błędów).

Wyjaśnienia

  • Twój program / funkcja zostanie uruchomiona bez wprowadzania danych (chyba że jest napisana w języku, który absolutnie wymaga danych wejściowych do działania, w którym to przypadku zostanie uruchomiona z najprostszym możliwym wejściem).

  • Jeśli produkujesz dane wyjściowe, możesz również utworzyć jeden końcowy znak nowej linii, jeśli chcesz, ale nie jest to obowiązkowe.

  • Definicja „zapisu błędu na standardowe wyjście”, którą implementuje program, musi traktować co najmniej następujące przypadki jako błędy:

    • Standardowe wyjście nie istnieje (tzn. stdoutJest zamkniętym uchwytem pliku, nie istnieje żaden deskryptor pliku 1, lub te przypadki tłumaczą się na język i używany system operacyjny);
    • Standardowe wyjście odnoszące się do pliku na dysku, na którym nie ma już wolnego miejsca;
    • Standardowe wyjście podłączane do innego programu, który już zamknął swój koniec połączenia.

    i musi traktować co najmniej następujące przypadki jako sukces (tj. nie błąd):

    • Standardowe wyjście łączy się z terminalem i Hello, world!jest wyświetlane na ekranie.
    • Standardowe wyjście łączy się z plikiem i Hello, world!jest zapisywane w pliku.

    Możesz wybrać szczegóły, które liczą się jako błąd wyjściowy, o ile jest to zgodne z powyższymi zasadami.

  • Twój program / funkcja nie powinna ulec awarii po napotkaniu którejkolwiek z powyższych sytuacji błędów. Od Ciebie zależy, jakiego kodu wyjścia użyjesz.

  • Twój program / funkcja nie powinna opisywać charakteru napotkanego błędu w standardowym strumieniu błędów; powinien po prostu wydrukować ciąg określony powyżej. Zewnętrzne dane wyjściowe dotyczące błędu standardowego (np. Ostrzeżenia kompilatora) są legalne tylko wtedy, gdy są generowane bezwarunkowo, niezależnie od tego, czy wystąpi błąd, czy nie.

  • Twój program musi działać tylko na jednym systemie operacyjnym (chociaż musi to być ten, w którym wymienione wyżej błędy mają sens; starałem się, aby były one wystarczająco ogólne, aby działały na większości wielozadaniowych systemów operacyjnych dla konsumentów, ale dziwniejsze systemy operacyjne mogą być wykluczone z tego wyzwania). Jeśli Twojego programu nie można przenosić, w tytule zgłoszenia podaj założenia, które należy uruchomić.

  • To zadanie może nie być możliwe w każdym języku (nie każdy język pozwala programowi na obsługę błędów wyjściowych w niestandardowy sposób). Musisz wybrać język, w którym jest to możliwe.

  • Upewnij się, że Twój program / funkcja działa! Nie ufaj po prostu dokumentacji funkcji bibliotecznych, aby robić to, co mówią. Obsługa błędów w prostych funkcjach wyjściowych często okazuje się być zepsuta w praktyce, nawet jeśli funkcje twierdzą, że obsługują błędy w teorii.

Przypadki testowe

Oto sposób na symulację każdego z powyższych błędów bashw Linuksie (nie musisz używać Linuksa, ale prawdopodobnie jest to najłatwiejszy system do przetestowania tego):

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

Pierwsze dwie przypadki testowe są deterministyczne. Ostatni nie jest (zależy od warunków wyścigu); do celów testowych zalecam dodanie opóźnienia między uruchomieniem programu a rzeczywistym wyjściem do standardowego wyjścia, aby upewnić się, że warunki wyścigu zostaną rozwiązane w sposób, który ujawnia błąd.

Warunek zwycięstwa

To jest wyzwanie, więc krótszy jest lepszy. Jak (prawie) zawsze mierzymy długość programu w bajtach.


1
Czy wiesz, czy istnieje sposób na przetestowanie tego w systemie Windows? Mogę przetestować pierwsze kryterium, ale nie tę część, że dysk jest pełny ...
Stewie Griffin

Czy możesz użyć warunku ograniczenia wyścigu sleep 1 < test; (sleep 2; your_program_here) > test?
Neil,

Odpowiedzi:


6

Bash , 71 60 bajtów

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

Wypróbuj online!

Jak to działa

Po zapisaniu Hello, world!do zmiennej h wykonujemy następujące czynności.

Najpierw (echo $h)2>&-próbuje wydrukować Hello, world!do STDOUT. 2>&-jest wymagane, aby zapobiec wyświetlaniu echa komunikatu o błędzie: błąd zapisu: zły deskryptor pliku w przypadku niepowodzenia zapisu. Ponieważ pisanie do nazwanego potoku, który nie przyjmuje danych wejściowych, zabiłoby program Bash z sygnałem 13 (SIGPIPE), wykonujemy polecenie w podpowłoce ( (...)), więc tylko podpowłoka zostanie zabita.

Wreszcie, jeśli drukowanie do STDOUT nie powiedzie się, podpowłoka zakończy działanie z niezerowym kodem stanu (141 dla SIGPIPE, 1 dla błędu ogólnego), więc echo Error writing \"$h\">&2drukuje żądany komunikat do STDERR.



1

Zsh , 55 bajtów

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

W przeciwieństwie do swojego kuzyna Basha, Zsh odmawia śmierci z powodu pękniętej rury.

Wypróbuj online!


1

C (gcc) , 87 86 bajtów

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

Wypróbuj online!

Nie golfił

#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);
}

skąd wiesz, jaki jest zwrot? tutaj mówi tylko, że jest> = 0, aby wszystko było w porządku ...
RosLuP

putszwraca liczbę zapisanych bajtów lub -1 w przypadku błędu, więc zwraca 14 (Hello World plus nowy wiersz) lub -1 . (To może być specyficzne dla platformy, ale tak właśnie działa z glibc.)
Dennis

K & R2 twierdzi, że zwraca EOF [-1 w sposób praktyczny] w przypadku błędu; lub wartość nieujemna, jeśli wszystko jest w porządku
RosLuP

1
W PPCG języki są definiowane przez ich implementację, a gcc / glibc zachowują się tak, jak powiedziałem.
Dennis,

Wolę starą książkę
RosLuP,

1

PowerShell, 80 bajtów

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

wyjaśnione:

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

nie udało mi się tego wypróbować, gdy wystąpi błąd, ale zdecydowanie ~ powinno ~ działać.


Komunikat o błędzie należy zapisać w STDERR . Zapisanie go do STDOUT nie jest możliwe, jeśli błąd wystąpi podczas pierwszej próby zapisu.
Dennis,

@Dennis dzięki za to, tam zaktualizowane, nie przeczytałem w pełni pytania.
colsw

Afaict PowerShell wychwytuje tylko fatalne wyjątki, więc potrzebujesz Write-Host -ErrorAction Stopczegoś takiego. Ponadto throwprodukuje dodatkowe debugowanie informacji poza wierszem, który powinien wydrukować, który, nawiasem mówiąc, powinien mieć małą literę W i podwójne cudzysłowy wokół łańcucha HW.
Dennis,

@Dennis zmiażdżyły mnie dodatkowe informacje debugowania, odpowiedź została tam zaktualizowana.
colsw

1

JavaScript, 79 76 bajtów

try{(l=console).log(a="Hello, world!")}catch(e){l.error('Error writing '+a)}

Zauważ, że ciąg, który powinieneś wypisać 'Hello, world!', jest o jeden bajt dłuższy niż to, czego używasz. Przypuszczam też, że przypisanie ado wywołania console.logbyłoby krótsze (1B) i usunięcie średnika po l.log(a)zapisaniu kolejnego bajtu.
Łukasza

@Luke Dzięki, to był całkiem duży błąd!
Matthew Roh,

1
try{(l=console).log(a="Hello, world!")}catch(e){l.error('Error writing '+a)}dla 76 bajtów. Najpierw consolejest przypisany do l, następnie "Hello, world!'przypisany do a, a następnie wykonany.
Łukasza

0

Perl 5, 51 bajtów

wymaga -M5.01, co jest bezpłatne

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

Testowany w Strawberry Perl 5.24.0 przez uruchomienie programu w stanie, w jakim się znajduje (wydruk na standardowe wyjście) i uruchomienie

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

(wydrukowano do standardowego błędu). Nie wiem, jak testować pod kątem innych błędów przy użyciu Strawberry, ale powinny być obsługiwane tak samo…


O ile wiem, to nie działa. tio.run/nexus/bash#jY3NDoIwEITvfYq1IXCiiD83ys3Ei2/… (W łańcuchu również brakuje przecinka).
Dennis

Nie wiem, co zrobić z tą stroną, do której prowadzą linki; czy możesz wyjaśnić, proszę? Pamiętaj też, że skrypt musi działać tylko na jednym systemie operacyjnym. I dodam przecinek; dzięki.
msh210

Dane wyjściowe powinny być wyświetlane Hello, world!po, === 1 ===a nic po pozostałych. Debugowanie nie powinno wyświetlać nic po === 1 ===i Error writing "Hello, world!"po innych. Wiem, że twój program nie musi działać na TIO, ale print f...pokazuje zamierzone komunikaty o błędach, podczas gdy oryginalny program nie.
Dennis,

„Wyjście” i „Debugowanie” nie wyświetlają niczego, o ile widzę. Nie wiem też, jakie powinny być sekcje „Nagłówek” i „Stopka”. I zupełnie nie znam TIO, ale zauważ, że Strawberry Perl działa na MS Windows.
msh210

Porada dla Dennisa dotycząca pomysłu przechowywania łańcucha w zmiennej (choć prawdopodobnie pomyślałbym o tym, gdybym go tam nie widział).
msh210

0

REXX, 111 106 bajtów

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

Program polega na istnieniu strumienia zwanego „stderr”. Prawdopodobnie nie będzie tak w przypadku systemów IBM.


0

C, 77 bajtów

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

na wezwanie

main(){f(1); return 0;}

Na jakiej platformie to przetestowałeś? Nie działa w systemie Linux, jeśli zostanie napotkany uszkodzony potok.
Dennis,

0

R , 91 bajtów

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

Wypróbuj online!

Próbowałem go popsuć, uruchamiając go cat(s,file=12)zamiast cat(s), i wypisuje poprawny tekst na stderr. W invalid connectionprzeciwnym razie jest to błąd.


Masz pomysł, jak przetestować pod kątem innych błędów wyjściowych?
JayCe
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.