Intelligente Lösungen
in neuer Dimension

Linux-Shell: Pipe mit Stderr

Ich habe einen Linux-Prozess, der Nutzausgaben nach STDOUT schreibt und Fehlerausgaben nach STDERR. Ich möchte nun die Fehlerausgaben in einer Shell-Skript-Pipe bearbeiten und die Nutzausgaben wie gewohnt auf STDOUT belassen.

Diese Anleitung wurde erstellt mit Ubuntu-20.04.

Problemstellung

my-service.sh:

1
2
3
4
5
6
7
8
9
10
11
#!/bin/sh
#
# Gibt 1 2 3 auf STDOUT aus
# und A B C auf STDERR
#
echo 1
echo A >&2
echo 2
echo B >&2
echo 3
echo C >&2

Ich möchte in einem Wrapper-Skript – STDERR mit Zeitstempel versehen und nach /var/log/my-service.log schreiben – STDOUT “durchreichen”

1
2
3
4
5
6
7
$ ./my-service.sh
1
A
2
B
3
D

Erster Versuch

my-wrapper-1.sh:

1
2
#!/bin/sh
./my-service.sh 3>&1 1>&2 2>&3 | while read l; do echo "$(date "+%Y-%m-%d %H:%M:%S") ${l}"; done

Ausgaben:

1
2
3
4
5
6
7
$ ./my-wrapper-1.sh
1
2
3
2021-02-22 16:19:26 A
2021-02-22 16:19:26 B
2021-02-22 16:19:26 C

Wie gewünscht sind die STDERR-Zeilen mit Datum versehen, super!

1
2
3
4
5
6
7
8
9
$ ./my-wrapper-1.sh >/dev/null
1
2
3

$ ./my-wrapper-1.sh 2>/dev/null
2021-02-22 16:26:07 A
2021-02-22 16:26:07 B
2021-02-22 16:26:07 C

STDOUT und STDERR sind vertauscht!

Zweiter Versuch

my-wrapper-2.sh:

1
2
3
4
#!/bin/sh
{
./my-service.sh 3>&1 1>&2 2>&3 | while read l; do echo "$(date "+%Y-%m-%d %H:%M:%S") ${l}"; done
} 3>&1 1>&2 2>&3

Wie sieht es mit dem Umlenkungen aus?

1
2
3
4
5
6
7
8
9
uli@ulicsl:/tmp$ ./my-wrapper-2.sh >/dev/null
2021-02-22 16:29:38 A
2021-02-22 16:29:38 B
2021-02-22 16:29:38 C

uli@ulicsl:/tmp$ ./my-wrapper-2.sh 2>/dev/null
1
2
3

Super!

Final

my-wrapper.sh:

1
2
3
4
#!/bin/sh
{
./my-service.sh 3>&1 1>&2 2>&3 | while read l; do echo "$(date "+%Y-%m-%d %H:%M:%S") ${l}"; done
} 3>&1 1>&2 2>&3

Anwendung dann:

1
./my-wrapper.sh 2>>/var/log/my-service.log

Historie und Anmerkung

  • 2021-02-23: {} statt () da weniger Overhead
  • 2021-02-22: Erste Version