finde übereinstimmende file_ids in den dat-Dateien im Verzeichnis und kopiere sie in ein anderes Verzeichnis

473
Jasmine

Ich habe eine file_id = 840920und ich muss nur die untergeordneten Dateien auswählen, die zu der gehören file_id = 840920. Die Namen der Datendatei sind unterschiedlich, aber in allen Datendateien ist die ID der übergeordneten Datei verfügbar. Ein Beispiel eines Datensatzes wird angezeigt als:

445973129|2602325065|840920|1|RUPATXEM14|LVP|||20180924 18:25:10 445973130|2602325066|840920|2|RP_STG_TEST_WED|LVP|||20180924 18:23 

Deshalb möchte ich meine Suche nur für die dritte Spalte zuordnen und diese dat-Dateien extrahieren und in einen anderen Ordner kopieren.

Unten ist mein Code in Unix, um das gleiche zu tun. Benötigen Sie Hilfe für weitere Vorschläge oder bessere Methoden, um mit dem gleichen Problem umzugehen. Meine Abfrage ist, dass ich matched_file_idWerte drucken kann, wenn ich die while-Schleife separat ausführe. Der Code wird jedoch nicht gedruckt und zeigt die matched_file_idWerte an, wenn ich sie in meinen Code einfügte: Irgendwelche Vorschläge bitte?

cat $TMP/TempBatchData.txt | while read FILE_ID #FILE_ID = 840920 do for file in *CDI*.dat; do echo $file >> all_CDI_LIST.txt done while IFS= read -r line; do matched_file_id=`cat $line | cut -f3 -d"|" | sort -u` # echo all the third  column values done < "all_CDI_LIST.txt"   if [[ $matched_file_id == $FILE_ID ]]; then  echo $line >> final_cdi_list.txt fi done done 
1

1 Antwort auf die Frage

0
Kamil Maciorowski

Probleme, verdächtige Fragmente:

  • $matched_file_identhält null oder mehr Werte, der Vergleich ist $FILE_IDnur dann erfolgreich, wenn es einen Wert gibt;
  • $matched_file_idwird einmal pro gesetzt line, Vergleich $FILE_IDwird einmal pro durchgeführt FILE_ID;
  • Es gibt ein Extra doneam Ende (?);
  • column values sollte zu einem Kommentar gehören;
  • Variablen werden nicht in Anführungszeichen gesetzt;
  • TMP sollte festgelegt werden.

Dies ist ein neu geschriebenes Verfahren. Es ist nicht völlig gleichwertig, aber der Ansatz scheint besser zu sein:

TMP="/the/right/path" find . -type f -name '*CDI*.dat' \ -exec sh -c ' <"$1" cut -f3 -d"|" | grep -qFx -f "$TMP/TempBatchData.txt" ' sh {} \; -print > final_cdi_list.txt 

Erläuterung:

  1. findfindet alle Dateien, die dem *CDI*.datMuster entsprechen.
  2. Für jede solche Datei wird eine Shell ausgeführt, um eine Pipe zu verarbeiten.
  3. cut extrahiert die dritte Spalte.
  4. grepquietly ( -q) prüft, ob ein literaler String ( -F) aus der angegebenen Datei ( -f) in der Ausgabe von cutals ganze Zeile ( -x) vorhanden ist.
  5. Wenn ja, findwird der Pfad zur Datei gedruckt.

Hinweise, Unterschiede, Macken:

  • findwirkt rekursiv. Um nur das aktuelle Verzeichnis ohne Unterverzeichnisse zu verarbeiten, benötigen Sie -maxdepth 1(nicht für POSIX erforderlich) oder eine POSIX-Lösung aus dieser Frage, oder lassen Sie die Shell expand *CDI*.dat( find *CDI*.dat -type f -exec …), die ihre Schattenseiten hat.
  • finddruckt Pfade mit führenden ./. Um Basisnamen zu erhalten, benötigen Sie -printf '%f\n'(nicht POSIX) anstelle von -printoder zB -exec basename {} \;(POSIX-kompatibel) statt -print.
  • grep -Fpasst auf wörtliche Zeichenfolgen. In Ihrem Code wird jede Zeile $TMP/TempBatchData.txtzweimal zweimal implizit verarbeitet:

    1. mit read FILE_ID(im Gegensatz zu read -r FILE_ID),
    2. innerhalb der [[ $matched_file_id == $FILE_ID ]](Vergleiche mit [[Perform Pattern Matching mit der nicht zitierten Zeichenfolge auf der rechten Seite, nicht nur ein einfacher Zeichenkettenvergleich).


    Ich bin mir nicht sicher, ob Sie sich darauf verlassen. Möglicherweise möchten Sie meinen Code anpassen.

  • Im Titel wird das Kopieren von Dateien in ein anderes Verzeichnis erwähnt. Bei meinem Ansatz brauchen Sie dafür nicht final_cdi_list.txtzu arbeiten. Verwenden Sie einfach -exec cp {} "/another/directory" \;statt -print.

Die Suche nach passenden Dateien kann mit der Sohle erledigt werden grep. Sie müssen jedoch das Muster anpassen. Beispiel:

grep -l '^[0-9]*|[0-9]*|840920|' *CDI*.dat 

Sie können viele Muster in einer Datei ( -f "$TMP/TempBatchData.txt") haben, aber sie müssen wie oben sein. Wenn zu viele Dateien übereinstimmen, erhalten *CDI*.datSie eine "Argumentliste zu lang" (der Ansatz, den for file in *CDI*.dat;Sie ursprünglich verwendet haben, ist dagegen immun).

Passen Sie möglicherweise Ihre Verzeichnisstruktur an (z. B. nur *CDI*.datDateien im aktuellen Verzeichnis und in den Unterverzeichnissen, rekursive Suche erlaubt oder überhaupt keine Unterverzeichnisse) und das Musterdateiformat. Die Idee ist zu verwenden

grep -lr -f "$TMP/TempBatchData.txt" 

oder etwas ähnliches. Hinweis -rist für POSIX nicht erforderlich, in diesem Beispiel ist die Bedeutung von GNU grep: Lesen Sie alle Dateien rekursiv unter dem aktuellen Arbeitsverzeichnis.

Ein einzelner grepProzess sollte schneller sein als jede Lösung, die find -execoder read(und in welcher Weise auch mit Zeichenfolgen übereinstimmt).