Möglichkeit, einen neuen Dateinamen bei Platzhaltereingabe zu schreiben?

Möglichkeit, einen neuen Dateinamen bei Platzhaltereingabe zu schreiben?

Ich verfüge aus wissenschaftlichen Praktika, an denen ich teilgenommen habe, über einige Erfahrungen mit Inix-Terminals und habe dabei hauptsächlich einige Dienstprogramme wie grep, awk, und verwendet sed. Es gibt jedoch eine Sache, die ich schon seit einiger Zeit herauszufinden versuche, um die Zahlenverarbeitung, die ich durchführen muss, wirklich viel effizienter zu gestalten.

Ich habe ein Skript run.awk, das einige Manipulationen an einer großen Sammlung massiver Textdateien vornimmt. Es nimmt die Datei chloride.out, extrahiert Daten daraus und schreibt sie chloride.cm.

Gibt es eine Möglichkeit, dieses Skript dazu zu bringen, Dateien basierend auf der anfänglichen Platzhalterphrase in der Shell aufzunehmen *.outund zu schreiben ?*.cm

Die Menge an Skripten, die ich zur Verarbeitung großer Datenmengen geschrieben habe und für die ich mehr als hundert Iterationen durchführen musste, ist einfach ärgerlich.

Am liebsten würde ich wissen, ob es eine Möglichkeit gibt, dies für alle meine Skripte über die Shell zu tun. Wenn es nicht in der Shell oder einem Äquivalent automatisiert werden kann, kann ich meine awkSkripte dann zumindest auf ähnliche Weise automatisieren, wie ich es beschrieben habe?

Antwort1

Sie können awk mit Sicherheit dazu bringen, mehrere Dateien über Platzhalter zu verarbeiten. Ein Vorschlag wäre, es run.awkals generische „Funktion“ zu belassen, die eine einzelne Datei annimmt und eine einzelne Ausgabedatei erzeugt, und es dann von einem anderen Skript aus aufzurufen, das sich dann um die Assimilation der Eingabe- und Ausgabedateien kümmern könnte.

Beispiel

Dies wäre ein Bash-Skript, wir können es nennen awk_runner.bash.

#!/bin/bash

for ifname in *.out; do 
  ofname=${ifname/.out/.cm}
  printf "IN: %s, OUT: %s\n" $ifname $ofname
  printf "running run.awk with %s & %s\n\n" $ifname $ofname

  run.awk $ifname $ofname
done

Beispiellauf

Ich habe ein Beispielverzeichnis mit einigen Testdateien darin erstellt.

$ touch file{1..4}.out

Dadurch wurden 4 Dateien erstellt:

$ ls -1
file1.out
file2.out
file3.out
file4.out

Jetzt führen wir unser Skript aus:

$ ./awk_runner.bash
IN: file1.out, OUT: file1.cm
running run.awk with file1.out & file1.cm

IN: file2.out, OUT: file2.cm
running run.awk with file2.out & file2.cm

IN: file3.out, OUT: file3.cm
running run.awk with file3.out & file3.cm

IN: file4.out, OUT: file4.cm
running run.awk with file4.out & file4.cm

Nach jeder Zeile, die mit „running…“ beginnt, könnte unser Skript von hier aus ausgeführt werden.

Dateien in einer Liste

Angenommen, wir verwenden statt des Platzhalters *.outeine Datei mit einer Liste von Dateinamen, etwa:

$ cat filelist.txt 
file1.out
file2.out
file3.out
file4.out

Wir könnten diese modifizierte Version unseres Skripts verwenden, die eine whileSchleife anstelle einer forSchleife verwendet. Nennen wir nun diese Variante des Skripts awk_file_runner.bash:

#!/bin/bash

while read ifname; do 
  ofname=${ifname/.out/.cm}
  printf "IN: %s, OUT: %s\n" $ifname $ofname
  printf "running run.awk with %s & %s\n\n" $ifname $ofname

  run.awk $ifname $ofname
done < filelist.txt

Diese Version des Skripts liest die Eingabe aus der Datei filelist.txt:

done < filelist.txt

whileDann verwenden wir für jeden Durchlauf der Schleife den readBefehl, um eine Zeile aus der Eingabedatei einzulesen.

while read ifname; do

awkAnschließend führt es alles auf die gleiche Weise wie das erste Skript aus, indem es das Skript ausführt, run.awkwährend es jede Zeile der Datei durchläuft.

Antwort2

Anstatt einen Shell-Wrapper zu schreiben und für jede verarbeitete Datei eine neue awk-Instanz zu erzeugen, können Sie dies direkt in awk tun. Wenn Sie bereits ein awk-Skript haben, können Sie mit der Variable FILENAME auf die aktuelle Datei zugreifen. Wenn Sie also ausführen , können Sie mit FILENAME feststellen, ob Sie mit Datei1 oder Datei2 arbeiten. Sie können auch on / in awk awk 'some commands' file1 file2verwenden . Wenn Sie also ein awk-Skript wie haben>printprintf

/pattern/{ print $1,$3 }

Sie könnten leicht tun

/pattern/{ print $1,$3 > FILENAME".processed" }

oder verwenden Sie es, FNR=1um zu erkennen, wenn Sie sich in einer neuen Datei befinden, und erstellen Sie eine Variable, um komplexere Manipulationen am Dateinamen vorzunehmen. Wie das Ersetzen einer .inErweiterung durch .out, wie in

sauer@humpy:/tmp$ grep . file*.in
file1.in:a
file1.in:b
file2.in:c
sauer@humpy:/tmp$ awk 'FNR=1{out=FILENAME;sub("\.in$",".out",out)} {print "processed"$0 > out}' file*.in
sauer@humpy:/tmp$ grep . file*.out
file1.out:processeda
file1.out:processedb
file2.out:processedc

Ich verwende grep .hier, um den Dateinamen und den Inhalt mehrerer Dateien anzuzeigen, was auch ein lustiger Trick ist. Aber das Wichtigste ist, den Wert der outVariablen auf eine geänderte Version von zu setzen, FILENAMEwenn FNRsich dieser auf 1 ändert (damit wir uns in Zeile 1 der Datei befinden) und dann alle Ausdrucke auf umzuleiten . Beachten Sie, dass dies leicht gefährlich ist, da eine Nichtübereinstimmung der Erweiterung zu keiner Ersetzung führt und Ihre Eingabedateien überschrieben werden. Daher wäre es gut, eine ausfallsichere Prüfung hinzuzufügen, um dies oder etwas Ähnliches outsicherzustellen . Das bleibt dem Leser als Übung überlassen. ;)out != FILENAME

Wenn Sie eine Datei mit einer Liste von Dateinamen benötigen, ist es am einfachsten, sie wie folgt auszuführen:

awkscript $(< /path/to/filename_list_file )

Dadurch wird der Inhalt übernommen filename_list_fileund in die Befehlszeile eingefügt.

verwandte Informationen