maplecut
Anmeldungsdatum: 7. Februar 2011
Beiträge: 239
Wohnort: Oberschwaben
|
Aus stündlichen Messdatendateien der Form "name_YYYYmmhh.csv" will ich aus der jeweils neuesten Datei die letzten fünf Zeilen, die "5_" enthalten, ausgeben lassen. Das geht, wie gewünscht, mit:
grep "5_" `ls -t | head -n1` | tail -n5
11.04.2017 13:33:50 5_exp 35552
11.04.2017 13:34:00 5_imp 10
11.04.2017 13:34:00 5_exp 35584
11.04.2017 13:34:10 5_imp 10
11.04.2017 13:34:10 5_exp 35617
Ich brauche das aber als Datei zur Weiterverarbeitung. Jedoch bekomme ich mit
grep "5_" `ls -t | head -n1` | tail -n5 > lastfile.txt
nur eine leere Datei. Was mache ich falsch? Oder gibt es einen anderen Weg? Danke und Grüße!
|
fleet_street
Top-Wikiautor
Anmeldungsdatum: 30. August 2016
Beiträge: 2138
Wohnort: Hunsrück
|
Und wenn du die Reihenfolge änderst?
ls -t | head -n1 | grep "5_" | tail -n5 > lastfile.txt
|
maplecut
(Themenstarter)
Anmeldungsdatum: 7. Februar 2011
Beiträge: 239
Wohnort: Oberschwaben
|
Unverändert – leere Datei! ☹
|
track
Anmeldungsdatum: 26. Juni 2008
Beiträge: 7174
Wohnort: Wolfen (S-A)
|
Du läufst gerade mit Volldampf auf ein bekanntes Problem: "Parse niemals die Ausgabe von ls !". Klar dass er in Teufels Küche kommt, sonbald da mal ein Leerzeichen, ein Verzeichnis oder sonst irgend etwas nicht ganz stromlinienförmiges kommt. Guck Dir doch einfach mal an, was in den einzelnen Schritten tatsächlich herauskommt, dann siehst Du auch warum: | ls -t | head -n1
grep "5_" $(ls -t | head -n1)
|
😬 Eine saubere Lösung ginge im Grunde nur mit einer for -Schleife, zu Fuß: (oder alternativ mit find ) | for f in * ; do
if [ -f "$f" -a "$f" -nt "$neueste" ]; then
neueste="$f"
fi
done
echo "$neueste"
grep 5_ "$neueste" | tail -5 > lastfile.txt
|
Beachte bitte überall das "Quoting" ! - sonst ist es ganz sicher nicht wasserdicht. LG, track
|
seahawk1986
Anmeldungsdatum: 27. Oktober 2006
Beiträge: 11179
Wohnort: München
|
Oder quickt & dirty mit Python3:
| #!/usr/bin/env python3
import glob, os
for file in sorted(glob.glob("5_*"), key=os.path.getmtime)[-5:]: print(file)
|
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 12822
|
fleet_street schrieb: Und wenn du die Reihenfolge änderst?
ls -t | head -n1 | grep "5_" | tail -n5 > lastfile.txt
Das macht etwas völlig anderes. (achte auf die Backticks)
|
D630
Anmeldungsdatum: 24. Juli 2013
Beiträge: 329
|
In bash und zumindest mit sort und stat aus coreutils 8.26 sollte sowas auch ok sein im Sinne von "safe": | #!/usr/bin/env bash
eval "$(
stat --printf="_=%Y grep -F 5_ \$%N | tail -n 5; exit \$PIPESTATUS;\n" "$PWD/"* |
LC_ALL=C sort -r -k 1g;
)";
|
:
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 12822
|
D630 schrieb: In bash und zumindest mit sort und stat aus coreutils 8.26 sollte sowas auch ok sein im Sinne von "safe": | #!/usr/bin/env bash
eval "$(
stat --printf="_=%Y grep -F 5_ \$%N | tail -n 5; exit \$PIPESTATUS;\n" "$PWD/"* |
LC_ALL=C sort -r -k 1g;
)";
|
Ohjeh! Du sortierst nicht numerisch hier. Sollte die Anzahl der Stellen von %Y in der Menge der Dateien wechseln, hast Du ein Problem. Ist zwar nicht sehr wahrscheinlich, aber immerhin. Es auch einige Verschwendung ein Skript zu generieren, das alle Dateien beinhaltet, nur um dann die Shell bei der ersten Zeile aussteigen zu lassen. Übrigens brauchst Du $PIPESTATUS gar nicht, denn exit nimmt sowieso den letzten Exit-Code: exit [n]
Cause the shell to exit with a status of n. If n is omitted, the exit status is that of the last com‐
mand executed. A trap on EXIT is executed before the shell terminates. Außerdem ist eval böse und auch unnötig, um die neueste Datei zu ermitteln. So ist das deutlich robuster: | newest_file=$(stat --printf '%Y %n\0' * | sort -rnz | sed -nz '1 {s#^[0-9]* ##p;q}')
|
Wer es etwas lesbarer als mit sed haben möchte: | newest_file=$(stat --printf '%Y %n\0' * | sort -rnz | head -1z)
newest_file="${newest_file#* }"
|
Beides funktioniert übrigens in der sh - man braucht keine bash . Gesamtlösung könnte dann so aussehen | newest_file=$(stat --printf '%Y %n\0' * | sort -rnz | sed -nz '1 {s#^[0-9]* ##p;q}')
fgrep 5_ "$newest_file" | tail -5 > lastfile.txt
|
fgrep statt grep , weil kein Regexmatch benötigt wird. Man kann es auch in eine Zeile quetschen und $newest_file sparen, aber dann wird es etwas unleserlich.
|
D630
Anmeldungsdatum: 24. Juli 2013
Beiträge: 329
|
Also sooo schrecklich finde ich es nun nicht, zumal ich die Wörtchen "sollte sowas" benutzt habe (falls es hier möglichst nur Standard-Antworten geben soll, mir einfach kurz mal ein Signal geben, dann halte ich mich zurück). In bash ist es schlicht langsamer (in mksh sieht es aber wieder anders aus). Ja, und in dash müssten dann – wie man es sonst macht – die \0 her, weil POSIX noch kein $'' -Quoting kennt (ist aber wohl schon geplant): | #!/usr/bin/env dash
eval "$(
QUOTING_STYLE=shell stat --printf="_=%Y grep -F 5_ %N | tail -n 5; exit;\0" "$PWD/"* |
LC_ALL=C sort -r -z -k 1n;
)";
|
:
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 12822
|
D630 schrieb: Also sooo schrecklich finde ich es nun nicht, zumal ich die Wörtchen "sollte sowas" benutzt habe (falls es hier möglichst nur Standard-Antworten geben soll, mir einfach kurz mal ein Signal geben, dann halte ich mich zurück).
Nee, wie soll das gehen? Dann müsste erst mal jemand definieren, was eine Standardantwort ist... ☺
In bash ist es schlicht langsamer (in mksh sieht es aber wieder anders aus). Ja, und in dash müssten dann – wie man es sonst macht – die \0 her, weil POSIX noch kein $'' -Quoting kennt (ist aber wohl schon geplant): | #!/usr/bin/env dash
eval "$(
QUOTING_STYLE=shell stat --printf="_=%Y grep -F 5_ %N | tail -n 5; exit;\0" "$PWD/"* |
LC_ALL=C sort -r -z -k 1n;
)";
|
Ich kann mich nicht dran gewöhnen... ☺ Warum verwendest Du eigentlich "$PWD" hier? Das ist doch überflüssig.
|
frostschutz
Anmeldungsdatum: 18. November 2010
Beiträge: 7656
|
for lastfile in name_*; do continue; done
grep "_5" "$lastfile" | tail -n 5 Bei deinem ursprünglichen Befehl wäre set -x nicht verkehrt. Dann weisst vielleicht eher was da passiert.
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 12822
|
frostschutz schrieb: for lastfile in name_*; do continue; done
grep "_5" "$lastfile" | tail -n 5
Das selektiert nicht nach Änderungszeit. Da musst Du es schon so machen wie track das gebaut hat.
|
maplecut
(Themenstarter)
Anmeldungsdatum: 7. Februar 2011
Beiträge: 239
Wohnort: Oberschwaben
|
Vielen Dank für die vielen Antworten bisher! Ich komme erst jetzt wieder dazu, mich der Sache zu widmen. Werde die Vorschläge mal ausprobieren. Die Lösung mit Python ist interessant, weil es letztendlich darum geht, einem Python-Messprogramm, bei eventuellem Neustart, die zuletzt gespeicherten Werte als Startwerte mitzuteilen, damit es daran anknüpfen kann. Meine ursprüngliche Idee war, das Python-Skript aus einem Bash-Skript zu starten, das zuvor diese letzten Werte sucht und in eine Datei schreibt, die dann vom Messprogramm eingelesen wird. Wenn ich das Ganze gleich in Python machen kann, ist das natürlich viel besser. Grüße!
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 12822
|
maplecut schrieb:
Wenn ich das Ganze gleich in Python machen kann, ist das natürlich viel besser.
Genau! Dann brauchst Du auch kein externes Programm, sondern kannst das in Dein Messprogramm integrieren.
|
maplecut
(Themenstarter)
Anmeldungsdatum: 7. Februar 2011
Beiträge: 239
Wohnort: Oberschwaben
|
Habe folgendes gefunden und wandle es für mich noch ab:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 | import glob, os
dateipfad = "digit*"
# letzte (neueste) Datei finden, die mit "digit" anfaengt:
for suche in sorted(glob.glob(dateipfad), key=os.path.getmtime)[-1:]:
filename = suche
# in gefundener Datei alle Zeilen finden, die einen bestimmten String enthalten
# und darin den Inhalt einer bestimmten Spalte verwenden:
with open(filename, "r") as origin:
for line in origin:
if not "5_" in line:
continue
line = line.split(' ')[3]
print(int(line))
|
liefert mir schon mal die gewünschten Werte. Grüße! Bearbeitet von rklm: Syntax!
|