Nowe posty

Autor Wątek: Przechwycenie błędu  (Przeczytany 4883 razy)

kosiek

  • Gość
Przechwycenie błędu
« dnia: 2011-11-10, 00:56:32 »
Witam.
Chciałem zapytać zapewne o podstawową rzecz, ale próbuję na różne sposoby i nie mogę osiągnąć tego czego oczekuję.
Otóż mam skrypt, który uruchamia zewnętrzny plik wykonywalny, w którym są regułki iptables.
Jeżeli, w którejś z regułek zrobię celowo błąd to wyrzuca błąd:
/iptables-test1]: ereiptables: not found
W jaki sposób przechwycić, że jeżeli podczas wykonywania polecenia ./iptables-test zostanie cokolwiek zwrócone to żeby wyświetlił błąd?

Z góry dziękuję za pomoc.

Offline ultr

  • Users
  • Guru
  • *****
  • Wiadomości: 1177
    • Zobacz profil
Przechwycenie błędu
« Odpowiedź #1 dnia: 2011-11-10, 01:37:32 »
Jeśli wywołujesz zewnętrzny skrypt, a w nim nie obsługujesz błędów, to niestety nie będziesz mógł skorzystać z wartości zwracanej przez uruchamiany program (np. iptables). Jeśli jest niezerowa, to z reguły oznacza to wystąpienie błędu.

Jeśli możesz edytować te zewnętrze pliki, to najlepiej dodać w nim do każdej linii:
... || exit 1
(tak jak w pliku 2.sh poniżej)
Dzięki temu przy pierwszym błędzie wewnętrzny skrypt zostanie przerwany i zwróci wartość 1 (niezerową, więc błąd).
W głównym programie w taki sam sposób możesz ten błąd przechwycić:
./skrypt2.sh || echo "Wystapil blad w skrypcie 2."
1.sh:
#!/bin/sh
./2.sh || echo "Blad w skrypcie 2.sh"
exit 0
2.sh:
#!/bin/sh
echo "A"
ech  "B"
echo "C" || exit 1
ech  "D" || exit 1
echo "E" || exit 1
echo "F" || exit 1
echo "G" || exit 1
exit 0
Odpalenie ./1.sh zakończy się po nieudanej próbie wyświetlenia "D".

----

Możesz także czytać standardowe wyjście błędów i zakładać, że jeśli coś się na nim pojawi, to wystąpił błąd. Ale to nie jest zbyt dobre podejście i może być zawodne.

kosiek

  • Gość
Przechwycenie błędu
« Odpowiedź #2 dnia: 2011-11-10, 08:42:49 »
A jeżeli reguły iptables mam w tym pliku wpisane linijka po linijce to czy ten problem zostanie rozwiązany poprzez wczytanie pliku z regułkami linijka po linijce i komenda iptables będzie wykonywana z || exit 1?
Czy takie rozwiązanie również nasuwa pewne komplikacje?

Offline ultr

  • Users
  • Guru
  • *****
  • Wiadomości: 1177
    • Zobacz profil
Przechwycenie błędu
« Odpowiedź #3 dnia: 2011-11-10, 12:36:19 »
Całkiem dobry pomysł jeśli ten zewnętrzny skrypt zawiera dokładnie jedno polecenie na linię.
Wczytujesz linia po linii i wykonujesz je sprawdzając wynik.

Tylko wyniku nie możesz sprawdzać już dołączając
|| ...
bo podane dalej polecenia zostaną wykonane w podpowłoce, a więc nie pozwolą przerwać wykonywania całego skryptu.
Musisz sprawdzić zmienną $? lub użyć danego polecenia jako wartości logicznej dla if-a (jak poniżej).

1.sh:
#!/bin/bash

while read -r command; do
        if [ -z "$command"          ]; then continue; fi
        if [ "${command:0:1}" = "#" ]; then continue; fi
        if ! $command; then
                echo ">>> Error while executing:"
                echo ">>>   $command"
                exit 1
        fi
done < 2.sh

exit 0
2.sh:
#!/bin/sh
echo A
echo B
ech C
echo D
echo E
Powyższy skrpt 1.sh dodatkowo ignoruje puste linie i linie zaczynające się od #, więc można sobie komentować plik 2.sh.
Jest to też konieczne dla pominięcia pierwszej linii skryptu zaczynającej się od shebanga.

jk33

  • Gość
Przechwycenie błędu
« Odpowiedź #4 dnia: 2011-11-10, 22:52:35 »
Pytanie czy warto. Moim zdaniem wystarczy:
#!/bin/sh -e 

....
pozdrawiam

kosiek

  • Gość
Przechwycenie błędu
« Odpowiedź #5 dnia: 2011-11-11, 14:49:05 »
#!/bin/sh -e
clear

if ./iptables-test
then
    echo 'test'
else
    echo 'test2'
fi
zwraca za każdym razem 'test' niezależnie od tego czy  w iptables-test jest błąd czy go nie ma.

Offline ultr

  • Users
  • Guru
  • *****
  • Wiadomości: 1177
    • Zobacz profil
Przechwycenie błędu
« Odpowiedź #6 dnia: 2011-11-11, 15:06:34 »
Ten parametr -e musiałbyś umieścić w skrypcie iptables-test, żeby to działało.

kosiek

  • Gość
Przechwycenie błędu
« Odpowiedź #7 dnia: 2011-11-11, 15:47:42 »
Ok tak działa tak jak należy, ale chyba zastosuję jednak odczytywanie linia po linii bo wtedy mogę zwrócić tą regułę, na której się wyłożyło.

kosiek

  • Gość
Przechwycenie błędu
« Odpowiedź #8 dnia: 2011-11-11, 16:08:45 »
A jeszcze mam pytanie.
Czy jest możliwość przechwycenia tego komunikatu błędnego, który zwraca konsola po wywołaniu np.
fdfiptables -A INPUT --protocol tcp --destination-port 22 -j ACCEPT
Czyli zwrócone:
./1.sh: line 6: fdfiptables: nie znaleziono polecenia
chciałbym przechwycić.
Tak żebym mógł również zwrócić jaki błąd wystąpił.

Offline ultr

  • Users
  • Guru
  • *****
  • Wiadomości: 1177
    • Zobacz profil
Przechwycenie błędu
« Odpowiedź #9 dnia: 2011-11-12, 16:03:45 »
1.sh:
#!/bin/bash

while read -r command; do
        if [ -z "$command"          ]; then continue; fi
        if [ "${command:0:1}" = "#" ]; then continue; fi
        if ! output=`$command 2>&1`; then                        # tutaj
                echo ">>> Error while executing:"
                echo ">>>   $command"
                echo ">>> Message:"                              # tutaj
                echo ">>>   $output"                             # i tutaj
                exit 1
        fi
done < 2.sh

exit 0
2.sh:
#!/bin/sh
echo A
echo B
ech C
echo D
echo E