Wyślij wyjście bash -x do pliku dziennika bez przerywania standardowego wyjścia

12

Czy istnieje sposób na przesłanie wyświetlanych informacji poprzez uruchomienie skryptu bash z opcją -x do pliku, bez zmiany standardowego wyjścia widzianego przez użytkownika uruchamiającego skrypt?

Jest to funkcja debugowania, którą chciałbym wdrożyć w skrypcie bash, którego często używamy.

Bardzo mile widziane.

przepraszam doktorze różu
źródło

Odpowiedzi:

21

Dane wyjściowe z -x są przesyłane do stderr, a nie do standardowego. Ale nawet to może stanowić problem - wiele skryptów będzie miało funkcjonalne zależności od zawartości stderr, a jego bałaganem jest mieszanie strumieni debugowania i stderr w niektórych przypadkach.

Wersje Bash> 4.1 oferują inne rozwiązanie: zmienna środowiskowa BASH_XTRACEFD umożliwia określenie deskryptora pliku, który będzie używany do wysyłania strumienia debugowania. Może to być plik lub potok lub dowolna inna dobroć uniksowa.

# Use FD 19 to capture the debug stream caused by "set -x":
exec 19>/tmp/my-script.log
# Tell bash about it  (there's nothing special about 19, its arbitrary)
export BASH_XTRACEFD=19

# turn on the debug stream:
set -x

# run some commands:
cd /etc
find 
echo "Well, that was fun."

# Close the output:
set +x
exec 19>&-

# See what we got:
cat /tmp/my-script.log

Przy odrobinie kręcenia możesz robić inne rzeczy - na przykład robić tee na strumieniach stdout i / lub stdin oraz przeplatać je z wyjściem debugowania, aby Twój dziennik był bardziej kompletny. Aby uzyskać więcej informacji na ten temat, zobacz /programming/3173131/redirect-copy-of-stdout-to-log-file-from-within-bash-script-itself .

Dużą zaletą tego podejścia w porównaniu z alternatywami jest to, że nie ryzykujesz zmian w zachowaniu twojego skryptu poprzez wstrzykiwanie wyników debugowania do stdout lub stderr.

Stabledog
źródło
Zobacz także tutaj, jak znaleźć nieużywany deskryptor pliku.
jarno
Czy konieczne jest zamknięcie deskryptora pliku (tj. Linii exec 19>&-)? Z mojego doświadczenia wynika, że ​​jest on zamykany automatycznie po zakończeniu skryptu.
jarno
1
Powyższy kod nie zakłada, że ​​uruchamiasz skrypt, ani jak długo może on być skryptu itp. Prawdą jest, że jeśli zrobisz to, co robi ten fragment kodu i umieścisz go w skrypcie, uchwyt pliku będzie być zamknięte tylko dlatego, że cała powłoka znika na końcu skryptu. W takim przypadku nie trzeba ściśle zamykać uchwytu. Ale ogólnie, gdy kodujesz w stosunku do zasobu, dobrą praktyką jest zamykanie tego, co otworzyłeś, ponieważ wtedy twój kod może być używany w szerszym kontekście, gdzie bardziej prawdopodobne jest, że porządkowanie jest ważne.
Stabledog
Dlaczego eksportujesz BASH_XTRACEFD? Dlaczego nie ustawić tej wartości?
jarno
W każdym razie alternatywnym sposobem zamknięcia deskryptora pliku jest ustawienie nowej wartości (np. Null) dla BASH_XTRACEFD lub jej rozbrojenie.
jarno
4

set -xnie wysyła niczego na standardowe wyjście, więc nie ma problemu. Co ona ma zrobić, to napisz do błędu standardowego, który jedzie do konsoli domyślnie.

To, co chcesz zrobić, to przekierować standardowe wyjście do innego pliku, takiego jak ten:

/bin/sh -x /my/script/file 2>/my/log/file
womble
źródło
1

Zobaczyć man tee.

Uruchamiasz go tak tee commandname filename, aby wyświetlał dane wyjściowe poleceń stdouti zapisywał je również filename.

Sven
źródło