IO-Umleitung mit mkpipe zu Protokollierungszwecken

3920
Hersheezy

Ich habe eine Reihe von Skripten, die die Ausgabe an stdout senden. Ich leite die Ausgabe in Dateien um, aber diese Dateien werden sehr schnell sehr groß. Zum Beispiel:

./script_with_lots_of_outpu.sh 2>&1 mylog.txt & 

Ich möchte die Ausgabe stattdessen an eine Named Pipe senden, so dass das folgende Skript die Datei, in die geschrieben wird, ändern kann:

#!/bin/bash if [ $# -ne 2 ]; then echo "USAGE: ./redir.sh pipename filename"  fi  pipename=$1 filename=$2 trap filename="`date +%s`$filename" 2 mkfifo $pipename  while [ 1 -eq 1 ] do read input echo $input >> $filename done < $pipename 

Man könnte diesem Skript ein CTRL-C (oder ein anderes Signal) senden und es würde effektiv dazu führen, dass die Ausgabe der Pipe in eine andere Datei schreibt (vorangestellt mit einem Zeitstempel).

Wenn ich dieses Skript starte und dann etwas daran wiederhole, beginnt es eine Menge leerer Zeilen zu schreiben:

 > ./redir.sh testpipe testfile & > echo "Dies ist ein Test"> Testpipe > wc -l Testdatei 627915 Testdatei 

Wie kann ich redir.sh nur in eine Datei schreiben, wenn die Pipe geschrieben wird, aus der sie liest?

BEARBEITEN

Das Endprodukt scheint wie folgt zu funktionieren. Ich muss noch mehr testen, um herauszufinden, ob es produktionswürdig ist

#!/bin/bash  if [ $# -ne 2 ]; then echo "USAGE: ./redir.sh pipename filename"  exit -1 fi  pipename=$1; rm $pipename; origname=$2.log filename=$2  rename() { filename="$origname-`date +%s`" mv $origname $filename nohup nice -n 20 tar -czvf $filename.tar.gz $filename & trap rename 2 }  mkfifo $pipename trap rename 2  while [ 1 -eq 1 ] do read input echo $input >> $origname done <> $pipename 
2

1 Antwort auf die Frage

2
Adam Zalcman

There is a caveat concerning the reading from a named pipe. When you open a named pipe your open() call hangs until a writer shows up. When a writer shows up subsequent read() calls will return whatever data the writer has written to the pipe. However, when the writer closes the pipe (or exits) the read() calls start returning 0 (rather than blocking).

This is the reason that instead of

int fd = open("testpipe", O_RDONLY); 

one might want to open a pipe like this

int fd = open("testpipe", O_RDWR); 

This way the process is not only the reader, but also the writer. Even though you never actually write anything to the pipe, this ensures that a writer exists and hence read() calls do not return 0, but block instead waiting for some writer to write something to the pipe.

Now, when your script does this:

while [ 1 -eq 1 ] do read input ... done < $pipename 

your shell opens the pipe for reading only (O_RDONLY).

The solution to your problem is to make shell open the pipe for both reading and writing like this:

while [ 1 -eq 1 ] do read input ... done <> $pipename 

Note the replacement of < $pipename with <> $pipename. This is what makes the shell open the pipe for both reading and writing (O_RDWR).

Es tut mir unglaublich leid, dass ich so lange auf die Antwort gewartet habe. Ihr Vorschlag hat wunderbar funktioniert. Hersheezy vor 12 Jahren 0