Ich muss Textzeichenfolgen aus einer einzelnen Datei extrahieren, die eine sehr lange Textzeile ohne Trennzeichen enthält. Anhand der folgenden Beispielzeile sind dies die folgenden bekannten Fakten:
??????? A1XXXXXXXXXX ??????? B1XXXX ??????? A1XXXXXXXXXX ??????? C1XXXXXXX
1. It contains 38 fixed width record types
2. The record marker is a 7 alphanumeric character followed by, for example, ‘A1’.
3. Each record type has varying widths, for example, A1 record type will have 10 characters following it, if B1 then 4, and if C1 then 7.
4. The record types aren’t clumped together and can be in any order. As in the example, its A1,B1,A1,C1
5. The example above has 4 records and each record type needs to go to separate files. In this case 38 of them.
??????? A1XXXXXXXXXX
??????? B1XXXX
??????? A1XXXXXXXXXX
??????? C1XXXXXXX
6. The record identifier, e.g. ????????A1, can appear in the body of the record so cannot use grep.
7. With the last point in mind, I was proposing 3 solutions but not sure on how to script this and of course would greatly appreciate some help.
a. Traverse through the file from the beginning and sequentially strip out the record to the appropriate output file. For example, strip out first record type A1 to A1file which I know is 10 characters long then re-interrogate the file which will then have B1 which I know is 4 chars long, strip this out to B1file etc.. <<< this seems painful >>
b. Traverse through the file and append some obscure character to each record marker within the same file. Much like above but not strip out. I understand it still will use the same logic but seems more elegant
c. I did think of simply using the proposed grep -oE solution but then re-interrogate the output files to see if any of the 38 record markers exist anywhere other than at the beginning. But this might not always work.
text-processing
sed
awk
Zacken
quelle
quelle
Antworten:
Wie wäre es mit grep
Dadurch wird jeder Datensatz jedes Datensatztyps in einer separaten Zeile gedruckt. Umleiten
grep
Ausgabe auf 3 Dateien mit dem NamenA1
,B1
,C1
bzw.,quelle
Hier ist eine mögliche Lösung mit gawks FPAT
Als Einzeiler:
quelle
FPAT
dass gawk Version 4 erforderlich ist. Siehe: linuxjournaldigital.com/linuxjournal/201109#pg98In Perl:
Rufen Sie es auf als:
Code getestet und funktioniert mit Ihrer angegebenen Eingabe.
Aktualisieren
In Ihren Kommentaren haben Sie ein "Unix-Äquivalent" der oben genannten angefordert. Ich bezweifle sehr, dass es so etwas gibt, da der Perl-Ausdruck, der zum Parsen Ihrer Zeile verwendet wird, ein sehr unregelmäßiger Ausdruck ist, und ich bezweifle, dass reguläre Vanille-Ausdrücke Ihr gegebenes Datenformat analysieren können: Er ist einem berühmten Ausdruckstyp zu ähnlich, den Regex kann 't parse (entspricht einer beliebigen Anzahl von
a
' s, gefolgt von der gleichen Anzahl vonb
's).In jedem Fall ist der nächste "Unix" -Ansatz, den ich finden kann, die Verallgemeinerung der Antwort von 1_CR . Sie sollten beachten, dass dieser Ansatz spezifisch für die GNU-Implementierung von ist
grep
und daher auf den meisten Unices nicht funktioniert. Im Gegensatz dazu sollte der Perl-Ansatz auf jeder Plattform, auf der Perl arbeitet, gleich funktionieren. Hier ist mein vorgeschlagener GNU-grep
Ansatz:Aktualisieren
Basierend auf den Anforderungen des OP in den Kommentaren kann der Dateiname nicht als Befehlszeilenargument übergeben werden, sondern im Skript wie folgt geöffnet werden:
Dies setzt voraus, dass Sie die Variable so deklariert haben
$input_file_name
, dass sie den Namen der Eingabedatei enthält.Zum Anhängen eines Zeitstempels an den Namen der Ausgabedatei können Sie die folgende
qx{}
Syntax verwenden: Zwischen den geschweiften Klammern können Sie einen beliebigen Unix-Befehl einfügen, der ausgeführt wird, und die Standardausgabe wird anstelle desqx{}
Operators zurückgelesen:Der
qx
Operator ist nicht auf geschweifte Klammern beschränkt. Verwenden Sie Ihr Lieblingszeichen als Trennzeichen. Stellen Sie nur sicher, dass es nicht in dem Befehl enthalten ist, den Sie ausführen müssen:und so weiter...
In einigen Perl-Codes sehen Sie möglicherweise backticks (
` `
), die stattdessen für diese Funktion verwendet werden, ähnlich wie die Shell.qx
Stellen Sie sich den Operator einfach als Verallgemeinerung von Backticks auf ein Trennzeichen vor.Übrigens gibt dies jeder Datei einen etwas anderen Zeitstempel (wenn die Differenz ihrer Erstellungszeiten zufällig eine endliche Anzahl von Sekunden ist). Wenn Sie dies nicht möchten, können Sie dies in zwei Schritten tun:
quelle