Wie automatisieren?
Ole
- programmiertechnik
Hallo,
ich suche nach einer Möglichkeit folgendes zu automatisieren:
Optimal wäre, wenn ich das ganze quasi in einem einzigen Programmaufruf (sowas wie ne EXE...ja, ihr ahnt es schon...unter Windows) lösen könnte.
Hat jemand einen einfachen Lösungsansatz dafür?
Btw. Ich möchte davon absehen jetzt auf die Schnelle noch C o.ä. lernen zu müssen ;).
Grüße
Ole
(8-)>
Mahlzeit,
Optimal wäre, wenn ich das ganze quasi in einem einzigen Programmaufruf (sowas wie ne EXE...ja, ihr ahnt es schon...unter Windows) lösen könnte.
Unter Windows? Viel Spaß, Sisyphos.
Normalerweise würde ich für solche Geschichten eine Kombination von find, grep, cut und sed vorschlagen ... oder halt Perl.
MfG,
EKKi
Hi
Normalerweise würde ich für solche Geschichten eine Kombination von find, grep, cut und sed vorschlagen ... oder halt Perl.
Hmmm...gab es da nicht die Unixtools for Windows ...
Grüße
Ole
(8-)>
Hallo
Normalerweise würde ich für solche Geschichten eine Kombination von find, grep, cut und sed vorschlagen ... oder halt Perl.
Hmmm...gab es da nicht die Unixtools for Windows ...
Cygwin ist erste Sahne.
Mich hat hier allerdings die ausschließliche Verwendung von Windows-Bordmitteln herausgefordert.
Freundliche Grüße
Vinzenz
Optimal wäre, wenn ich das ganze quasi in einem einzigen Programmaufruf (sowas wie ne EXE...ja, ihr ahnt es schon...unter Windows) lösen könnte.
Als Mac-User hättest du nun einen Hinweis auf den »Automator« erhalten, mit dem du sowas in ein paar Klicks (GUI, Baby!) hättest umsetzen können.
*stichel* ;)
Viele Grüße!
_ds
Hi
*stichel* ;)
*grummel* ;)
Grüße
Ole
(8-)>
Hallo Ole,
ich suche nach einer Möglichkeit folgendes zu automatisieren:
- Finde in Ordner X die Dateien (HTML) in denen der String A (eine Zeile) 2x vorkommt
- Gehe zu Fundstelle 2 in dieser Datei und kopiere diese und die Folgenden 19 Zeilen
- Ersetze String B (Teil von A) durch String C
- Füge den kopierten String an eine bestehende Datei an.
Optimal wäre, wenn ich das ganze quasi in einem einzigen Programmaufruf (sowas wie ne EXE...ja, ihr ahnt es schon...unter Windows) lösen könnte.
Hat jemand einen einfachen Lösungsansatz dafür?
Nein, keinen schnellen Lösungsansatz, aber einen Lösungsansatz.
Btw. Ich möchte davon absehen jetzt auf die Schnelle noch C o.ä. lernen zu müssen ;).
Nun ja, C wäre so ziemlich die letzte Hochsprache, die ich Dir für Zeichenkettenverarbeitung ans Herz legen würde ...
Nun zu meinem Vorschlag: Ich gehe davon aus, dass Du nach Möglichkeit mit Windows-Bordmitteln auskommen willst - und dass es sich um ein neueres Windows aus der NT-Familie handelt. Mein Vorschlag nutzt den Windows Scripting Host, wobei dieser wiederum die Kommandozeile, zum Beispiel CMD.EXE, benutzt.
- Finde in Ordner X die Dateien (HTML) in denen der String A (eine Zeile) 2x vorkommt
Diesen Schritt können wir leider nur beinahe von der Kommandozeile erledigen lassen:
FINDSTR /X /N /C:"A" X\*.html
liefert wegen /X - Suchstring entspricht einer ganzen Zeile /N - Gib die Zeilennummer vor jeder Trefferzeile an
folgende Ausgabe
<Pfad\zu\Datei>:<zeilennummer>:<suchtext>
a) Ermittle die Dateien, in denen die Zeichenkette zweimal vorkommt: <Pfad\zu\Datei> muss mindestens 2x untereinander stehen, d.h. betrachte jeweils nur die zweite Zeile zu jedem <Pfad\zu\Datei>
b) Verarbeite die so erhaltene Liste zeilenweise:
- Öffne die in der Zeile angegebene Datei und lese diese in ein Array ein.
- Gehe zu Fundstelle 2 in dieser Datei und kopiere diese und die Folgenden 19 Zeilen
- Kopiere aus dem Inhaltsarray den entsprechenden Ausschnitt (Slice) in eine Variable
- Ersetze String B (Teil von A) durch String C
- Ersetze im Inhaltsarray in der angegebenen Zeile String B durch String C - Speichere den geänderten Inhalt ab
- Füge den kopierten String an eine bestehende Datei an.
- Öffne die bestehende Datei und hänge den kopierten String an diese an.
Schritt: Auswahl der Programmiersprache Der Windows Scripting Host unterstützt eine Reihe von Programmiersprachen, zum Beispiel: - VB-Script - JScript - Perl - Python Die beiden erst genannten sollten Dir auf Deinem Windows-System auf jeden Fall zur Verfügung stehen. Da Du aus dem Webumfeld kommst, wählen wir JScript (die Microsoft-Variante von Javascript), da Dir dessen Syntax, Objekte ... bereits bekannt sind - auch wenn wir uns damit an anderer Stelle Probleme einhandeln.
Schritt: Umsetzung (ohne Fehlerbehandlung, die ist Dir überlassen)
Der Aufruf soll so erfolgen:
Skriptname Suchzeile Suchstring Ersatzstring Verzeichnis Logdatei
Netter wäre es natürlich, eine kleine HTA mit Eingabefeldern und Fileselectboxen zu erstellen.
/* ------------------------------------------------------------------------ */
// Wir brauchen ein Shell-Objekt, um das FINDSTR-Kommando abzusetzen
var WshShell = new ActiveXObject("WScript.Shell");
// übergebe die Kommandozeilenparameter an Variablen
// Beachte: Hier gehört grundsätzliche eine Fehlerbehandlung hin!
var suchzeile = WScript.Arguments(0);
var nadel = WScript.Arguments(1);
var ersatz = WScript.Arguments(2);
var verzeichnis = WScript.Arguments(3);
var logfile = WScript.Arguments(4);
// Beachte: Windows-Verzeichnispfade nutzen den Backslash, der ist in JScript
// Escapezeichen, wir müssen daher in den Pfadangaben die Backslashes verdoppeln
// Dazu nutzen wir eine selbstgeschriebene Funktion os_escape()
verzeichnis = os_escape(verzeichnis);
logfile = os_escape(logfile);
// Wir suchen nur HTML-Dateien (hier ggf. korrigieren)
var dateimaske = verzeichnis + "\*.html";
// Baue das Kommando zusammen, wir lassen es den Kommandozeileninterpreter ausführen
// In der Umgebungsvariablen %COMSPEC% ist der Interpreter zu finden
// /C sorgt dafür, dass er gleich wieder geschlossen wird
// Für die Anführungszeichen ist etwas Jonglieren notwendig
var command = "%COMSPEC% /C \"findstr /X /N /C:\"" + suchzeile + "\" " + dateimaske + "\""
// Führe das Kommando aus ...
var oExec = WshShell.Exec(command);
// ... und lese die Ausgabe in eine Variable ein
var zeilenliste = oExec.StdOut.ReadAll();
// Mögliche Debug-Ausgabe
// WScript.Echo(zeilenliste);
// Wir benötigen von jeder in der Zeilenliste aufgeführten Datei nur diejenigen,
// die mindestens zweimal auftreten - und zwar nur die zweite Fundstelle.
// Dafür ist die Funktion get_Files() zuständig
zeilenliste = get_Files(zeilenliste);
// Debugausgabe (hat's geklappt?)
// WScript.Echo(zeilenliste.join("\n"));
// Arbeite der Reihe nach die Dateien ab:
var anzahl = zeilenliste.length;
for (var i = 0; i < anzahl; i++) {
// Suchzeile verändern - und Originaltext zurückgeben
var text = bearbeite_datei(zeilenliste[i], nadel, ersatz);
// Originaltext loggen
haenge_text_an_log(logfile, text);
}
/* ------------------------------------------------------------------------
** Helferfunktionen
**
** string os_escape( string filename )
** Array get_Files( string zeilenliste )
** string bearbeite_datei( string eintrag, string nadel, string ersatz )
** string get_filename( string eintrag )
** int get_zeile( string eintrag )
** Array lese_datei_in_array( string filename )
** void schreibe_datei( string filename, string inhalt )
** void haenge_text_an_log(string filename, string inhalt )
** ----------------------------------------------------------------------*/
function os_escape(filename) {
// Backslashes in Dateinamen müssen verdoppelt werden.
// quick and dirty
return filename.replace("\\", "\\\\");
}
function get_Files(zeilenliste) {
// filtert aus der zeilenliste (eine Zeichenkette) die gewünschten Zeilen
// aus, d.h. jeweils die Zeile, in der das zweite Auftreten des Suchstrings
// innerhalb einer Datei vermerkt ist.
var ausgabe = new Array();
var zeilen = zeilenliste.split("\n");
var anzahl = zeilen.length;
var merker = "";
var auftreten = 0;
for ( var i = 0; i < anzahl; i++) {
// Abschnitte sind durch Doppelpunkt (:) getrennt
// Vorsicht, Laufwerksbuchstabe kann ein Problem sein
var inhalt = zeilen[i].split(":");
var filename = "";
if (inhalt.length == 3) {
// relative Pfadangabe
filename = inhalt[0];
}
else {
// Angabe mit Laufwerksbuchstabe
filename = inhalt[0] + ":" + inhalt[1];
}
if (filename != merker) {
// Erstes Auftreten,
// Setze merker auf neuen Wert
merker = filename;
// Setze auftreten auf 1
auftreten = 1;
}
else {
auftreten++;
if (auftreten == 2) {
// Diese Zeile benötigen wir
ausgabe.push(zeilen[i]);
}
// alle anderen interessieren auch nicht mehr :-)
}
}
return ausgabe;
}
function bearbeite_datei(eintrag, nadel, ersatz) {
// Kopiert aus einer Datei die Zeile mit dem Suchstring und
// die folgenden 19 Zeilen in eine Variable
// Ersetzt in der Suchzeile die Zeichenkette nadel durch die
// Zeichenkette ersatz
// Schreibt die geänderte Datei weg
// Gibt den gewünschten Text zurück
// Benutzt folgende Helferfunktionen
// - get_filename(eintrag)
// ermittelt aus einer der Ausgabe von FINDSTR /X /N entsprechenden
// Zeile den Dateinamen
// - get_zeile(eintrag)
// ermittelt aus ebensolchem Eintrag die Zeilennummer der Suchzeile
// - lese_datei_in_array(filename)
// das Äquivalent zu file() in PHP
// ausser dass die Zeilenenden bereits entfernt sind :-)
// - schreibe_datei(filename, inhalt)
// das Äquivalent zu file_put_contents() in PHP
var filename;
var zeile;
var inhalt;
var kopierbereich;
var offset = 19;
// Ermittele die zu öffnende Datei
filename = get_filename(eintrag);
// Ermittle die Zeile, in der der Suchstring zum zweiten Mal in der Datei vorkommt
zeile = get_zeile(eintrag);
// Debug-Ausgabe
// WScript.Echo(zeile);
// Lese die zu bearbeitende Datei in ein Array ein
inhalt = lese_datei_in_array(filename);
// Ermittle zu loggenden Text
kopierbereich = inhalt.slice(zeile - 1, zeile + offset);
kopierbereich = kopierbereich.join("\n");
WScript.Echo(kopierbereich);
// Verändere die Suchzeile
inhalt[zeile-1] = inhalt[zeile-1].replace(nadel, ersatz);
// WScript.Echo(inhalt[zeile-1]);
// Schreibe geänderte Datei weg
schreibe_datei(filename, inhalt.join("\n"));
// Gebe gesuchte Zeichenkette zurück
return kopierbereich;
}
function get_filename(eintrag) {
var inhalt = eintrag.split(":");
var filename = inhalt[0];
if (inhalt.length == 4) {
// Dateiname mit Laufwerksbezeichnung)
filename = inhalt[0] + ":\\" + inhalt[1];
}
return os_escape(filename);
}
function get_zeile(eintrag) {
var inhalt = eintrag.split(":");
if (inhalt.length == 4) {
return parseInt(inhalt[2]);
}
else {
return parseInt(inhalt[1]);
}
}
function lese_datei_in_array(filename) {
var fso, f, inhalt;
var ForReading = 1, ForWriting = 2;
// Wir brauchen ein FileSystemObject
fso = new ActiveXObject("Scripting.FileSystemObject");
// Oeffnen die Datei zum Lesen
f = fso.OpenTextFile(filename, ForReading);
// Lese Dateiinhalt in eine Zeichenkette
inhalt = f.ReadAll();
// Wandle diese in ein Array aller Zeilen um
inhalt = inhalt.split("\n");
// Schliessen die Datei
f.Close();
// Geben den Inhalt in Form des Arrays aller Zeilen zurück
return inhalt;
}
function schreibe_datei(filename, inhalt) {
var fso, f, inhalt;
var ForReading = 1, ForWriting = 2;
// Wir brauchen ein FileSystemObject
fso = new ActiveXObject("Scripting.FileSystemObject");
// Oeffnen die Datei zum Schreiben
f = fso.OpenTextFile(filename, ForWriting);
// Schreiben den Inhalt in die Datei
f.Write(inhalt);
// Schliessen die Datei
f.Close();
}
function haenge_text_an_log(filename, text) {
var fso, f;
var ForAppending = 8;
// Wir brauchen ein FileSystemObject
fso = new ActiveXObject("Scripting.FileSystemObject");
// Oeffnen eine Datei zum Anhaengen
f = fso.OpenTextFile(filename, ForAppending);
// Fuegen den Text am Ende an
f.Write(text);
// Schliessen die Datei
f.Close();
}
Wie bereits gesagt, die Fehlerbehandlung habe ich komplett Dir überlassen :-) Ein einfacher Test an der Kommandozeile hat bei mir das gewünschte Ergebnis erzielt. Du solltest Dir aber wirklich eine einfache HTML-Oberfläche dazu basteln und das ganze als HTA abspeichern.
Mit freundlichen Grüßen
Vinzenz
Hallo Vizenz,
meine Güte...da bin ich aber erstmal sprachlos :)
[...]
Ich werde mich mal durch die Scripte durchwühlen. Bin schwer beeindruckt.
Wie bereits gesagt, die Fehlerbehandlung habe ich komplett Dir überlassen :-)
Ein einfacher Test an der Kommandozeile hat bei mir das gewünschte Ergebnis
erzielt.
Du solltest Dir aber wirklich eine einfache HTML-Oberfläche dazu basteln
und das ganze als HTA abspeichern.
Sobald ich mich tiefer in die Materie eingearbeitet habe, werde ich das in Angriff nehmen.
Vielen, vielen Dank.
Grüße
Ole
(8-)>
Hallo Ole,
Ich werde mich mal durch die Scripte durchwühlen.
falls Du's noch nicht getan hast, wühl Dich durch die neue Version durch.
Die ist schon mal eine Klasse besser.
Bin schwer beeindruckt.
Danke!
Du solltest Dir aber wirklich eine einfache HTML-Oberfläche dazu basteln
und das ganze als HTA abspeichern.
das neue Skript sollte sich viel leichter über eine HTA steuern lassen.
Noch ein Tipp: Code für eine Verzeichnisauswahlbox findest Du auf meiner Testseite.
Freundliche Grüße
Vinzenz
Guten Morgen,
falls Du's noch nicht getan hast, wühl Dich durch die neue Version durch.
Die ist schon mal eine Klasse besser.
Auch wenn ich mich wiederhole:
Bin schwer beeindruckt.
das neue Skript sollte sich viel leichter über eine HTA steuern lassen.
Noch ein Tipp: Code für eine Verzeichnisauswahlbox findest Du auf meiner Testseite.
Ich arbeite noch daran das Ganze zu verstehen, ist ja weitgehend Neuland für mich...aber ich habe schlaue Bücher und das Internet...die Helfen :)
Danke :)
Ole
(8-)>
Hallo Ole,
das neue Skript sollte sich viel leichter über eine HTA steuern lassen.
Noch ein Tipp: Code für eine Verzeichnisauswahlbox findest Du auf meiner Testseite.Ich arbeite noch daran das Ganze zu verstehen,
wenn Du spezielle Fragen hast, stelle sie doch hier.
ist ja weitgehend Neuland für mich...
Wieso den das. Das meiste ist einfaches Javascript-kompatibles JScript.
Ich bin mir sicher, dass Du Dich darin ganz ordentlich auskennst :-)
aber ich habe schlaue Bücher
und das Internet...die Helfen :)
z.B. dieses Forum.
Ich habe gestern abend noch ein Problem entdeckt, für das ich bisher keine
befriedigende Lösung gefunden habe:
Doppelte Anführungszeichen in Suchzeile, Such- und Ersatzzeichenkette.
Der Windows Scripting Host schluckt diese bei der Übergabe auf der Kommandozeile.
Meine recht intensive Internet-Recherche zu diesem Thema war bisher erfolglos.
FINDSTR akzeptiert durchaus doppelt Anführungszeichen, diese müssen mit einem
Backslash maskiert werden, das ist also nicht das Problem. Man kriegt sie als
Kommandozeilenparameter nicht in die Anwendung.
Zwei Lösungen:
a) Erstelle eine HTA
Auf die Inhalte von Formularfelder kann problemlos zugegriffen werden.
b) Statt einer Serie von Parametern erfolgt die Parameterübergabe in Form
z.B. einer INI-Datei. Aus Dateien können Zeichenketten mit doppelten
Anführungszeichen problemlos eingelesen werden.
Todo:
Die Anführungszeichen müssen beim Aufruf von FINDSTR noch maskiert werden.
Freundliche Grüße
Vinzenz
Hallo Vinzenz,
Bin ebenfalls sehr beeindruckt. Gleich ein fertiges Programm, wow! Das Windows-Scripting kenne ich bis jetzt kaum (nur innerhalb von MS-Word), aber das ist ja jetzt ein super Studienmaterial, incl. Doku, vielen Dank, das kann ich sicher noch brauchen.
Ich persönlich hätte sowas ja mit Perl gelöst, zumindest teilweise, aber nur mit Bordmitteln ist auch nicht schlecht.
Gruß, Don P
Hallo Don P,
Bin ebenfalls sehr beeindruckt. Gleich ein fertiges Programm, wow!
danke.
Ich persönlich hätte sowas ja mit Perl gelöst, zumindest teilweise, aber nur mit Bordmitteln ist auch nicht schlecht.
Das war genau die Herausforderung, die mich motiviert hat.
Inzwischen hab' ich eine verbesserte Variante erstellt, siehe https://forum.selfhtml.org/?t=160894&m=1047574.
Eigentlich wollte ich ja den Postingtitel ändern. Da ich das Skript noch etwas zusammenstreichen musste, damit es die Grenzen der Forumssoftware noch einhält, hab' ichs im zweiten Anlauf vergessen.
Freundliche Grüße
Vinzenz
Hallo,
Ich habe meinen Code etwas revidiert.
Neu:
/**
* Schreibt den übergebenen Inhalt in die angegebene Datei. Falls die Datei nicht existiert,
* wird sie angelegt.
* <b>write_to_file</b>
*
* @param filename {string} Name der Datei, in die geschrieben werden soll
* @param content {string} Inhalt, der in die Datei geschrieben werden soll
* @param mode {int} entweder 2 (Inhalt wird überschrieben) oder 8 (Inhalt wird angehängt)
*/
function write_to_file(filename, content, mode) {
var fso, f;
fso = new ActiveXObject("Scripting.FileSystemObject");
f = fso.OpenTextFile(filename, mode);
f.Write(content);
f.Close();
}
/**
* Liest den Inhalt der angegebenen Datei in ein Array aller Zeilen.
* Die Zeilenenden werden dabei entfernt.
* Für die Fehlerbehandlung gilt das Gleiche wie bei write_to_file :-(
* <b>file</b>
*
* @param {string} filename Name der Datei, die eingelesen werden soll
* @return den Inhalt der Datei als Array der Zeilen
*/
function file(filename) {
var fso, f, inhalt;
fso = new ActiveXObject("Scripting.FileSystemObject");
f = fso.OpenTextFile(filename, 1); // 1: Nur-Lese-Modus
inhalt = f.ReadAll();
f.Close();
return inhalt.split("\n");
}
/**
* Extrahiert aus der übergebenen Zeichenkette die "Spalte" mit der Zeilennummer.
* Die übergebenen Zeichenketten sind vom Format:
* D:\test\t3.html:1:Das ist ein Text
* <b>extract_line_no</b>
*
* @param output_findstr {string} eine Zeile der Ausgabe von FINDSTR /X /N
* @return die Zeilennummer als Integer
*/
function extract_line_no(output_findstr) {
var content = output_findstr.split(":");
// Die Zeilennummer steht in der vorletzten Spalte
// Beachte die explizite Umwandlung in eine Integer
return parseInt(content[content.length - 2]);
}
/**
* Extrahiert aus der übergebenen Zeichenkette den Dateinamen.
* Die übergebenen Zeichenketten sind vom Format:
* D:\test\t3.html:1:Das ist ein Text
* D:\test\t3.html:3:Das ist ein Text
* <b>extract_filename</b>
*
* @param output_findstr {string} eine Zeile im Format der Ausgabe von FINDSTR /X /N
* @return den Dateinamen
*/
function extract_filename(output_findstr) {
var parts = output_findstr.split(":");
var filename = parts[0];
if (parts.length == 4) {
// Dateiname mit Laufwerksbezeichnung)
filename = parts[0] + ":" + parts[1];
}
return filename;
}
/**
* Windowsdateinamen verwenden den Backslash als Trennzeichen. Der Backslash ist in
* JScript jedoch Maskierungszeichen.
* <b>os_escape</b>
*
* @param path {string} Dateiname
* @return Zeichenkette mit verdoppelten Backslashes
*/
function os_escape(path) {
return path.replace("\\", "\\\\");
}
/**
* Kopiert aus der durch filename spezifizierten Datei die Zeile mit dem Suchstring
* und die folgenden Zeilen, deren Anzahl durch den Parameter offset bestimmt wird.
* In der Suchzeile wird das Vorkommen von search durch den Inhalt von replace ersetzt.
* Der Inhalt der Originalzeile und die offset folgenden wird zurückgegeben.
* <b>process_file</b>
*
* @param filename {string} Datei, die zu bearbeiten ist
* @param line_no {integer} Zeilennummer der gesuchten Zeile
* @param search {string} Suchstring innerhalb der Zeile
* @param replace {string} Ersatz für den Suchstring
* @param offset {integer} Anzahl der folgenden Zeilen, die benötigt werden
* @return String mit der Originalzeile und den gewünschten folgenden Zeilen
*/
function process_file(filename, line_no, search, replace, offset) {
// Lese die zu bearbeitende Datei in ein Array ein
var content = file(os_escape(filename));
// Kopiere zu loggende Zeilen ...
// Beachte: FINDSTR zählt die Zeilen von 1 im Gegensatz zu JScript
result = content.slice(line_no - 1, line_no + offset);
// ... und wandle diese in eine Zeichenkette um
result = result.join("\n");
// Ersetze in der Suchzeile das Auftreten von search durch den Inhalt von replace
content[line_no-1] = content[line_no-1].replace(search, replace);
// Schreibe geänderte Datei weg, überschreibe bisherigen Inhalt
write_to_file(filename, content.join("\n"), 2);
return result;
}
/**
* Filtert aus der Ausgabe von FINDSTR /X /N genau die Zeilen heraus, die das zweite
* Vorkommen der Suchzeile in der gleichen Datei angeben.
* <b>filter_list</b>
*
* @param output_findstr {string} Ausgabe von FINDSTR /X /N
* @return Array der relevanten Zeilen
*/
function filter_list(output_findstr) {
// nimmt die Einträge für den Rückgabewert entgegen
var filtered_list = new Array();
// für den Dateinamen der zuletzt bearbeiteten Zeile, anfangs leer
var previous = "";
// der wievielte Eintrag zur gleichen Datei
var count = 0;
// Splitte Ausgabe in Array auf
var rows = output_findstr.split("\n");
// Wieviele Zeilen hatte die Ausgabe von FINDSTR
var rowcount = rows.length;
// Durchlaufe die Zeilen der Ausgabe
for ( var i = 0; i < rowcount; i++) {
// Abschnitte sind durch Doppelpunkt (:) getrennt
// Vorsicht, Laufwerksbuchstabe kann ein Problem sein
var parts = rows[i].split(":");
var current = parts[0];
if (parts.length == 4) {
// Angabe mit Laufwerksbuchstabe
current = parts[0] + ":" + parts[1];
}
if (current != previous) {
// Erstes Auftreten: setze previous auf neuen Wert, initialisiere Zähler
previous = current;
count = 1;
}
else {
// Suchzeile mehrfach in der gleichen Datei vorhanden: zähle mit
count++;
if (count == 2) {
// Wir sind genau am zweiten Auftreten interessiert
filtered_list.push(rows[i]);
}
// alle anderen fallen genauso unter den Tisch wie das erste Auftreten :-)
}
}
return filtered_list;
}
/**
* Setzt in einer Kommandozeile FINDSTR /X /N mit den notwendigen Aufrufparametern ab.
* Gibt die Ausgabe des Kommandos zurück
* <b>get_output_findstr</b>
*
* @param searchrow {string} Suchzeile, die exakt übereinstimmen muss
* @param directory {string} Verzeichnis, in dem gesucht werden soll
* @param filemask {string} Dateiendung der Dateien, die durchsucht werden sollen
* @param recursive {boolean} Sollen Unterverzeichnisse mit durchsucht werden
* @return Zeichenkette mit der Ausgabe des FINDSTR-Kommandos
*/
function get_output_findstr(searchrow, directory, filemask, recursive) {
// Wir brauchen ein Shell-Objekt, um das FINDSTR-Kommando abzusetzen
var WshShell = new ActiveXObject("WScript.Shell");
// Schalter, die für FINDSTR zu setzen sind:
// /X Gibt Zeilen aus, die vollkommen übereinstimmen
// /N Gibt die Zeilennummer vor jeder Trefferzeile an
// /C:Zeichenfolge Sucht die Zeichenfolge buchstabengetreu
var options = "/X /N ";
// /S: Durchsuche auch alle Unterverzeichnisse
if (recursive) {
options += "/S ";
}
// Baue das Kommando für den Kommandozeileninterpreter zusammen
// In der Umgebungsvariablen %COMSPEC% ist der Interpreter zu finden
// /C sorgt dafür, dass er gleich wieder geschlossen wird
// Für die Anführungszeichen ist etwas Jonglieren notwendig:
// Das Kommando ist in doppelte Anführungszeichen zu setzen, der gesuchte Text
// übrigens auch und genauso die Pfadangabe für die Suche
var command = "%COMSPEC% /C "
+ "\"" // Anfang Kommando
+ "FINDSTR "
+ options
+ "/C:"
+ "\"" + searchrow + "\"" // Suchtext in doppelten Anführungszeichen
+ " " // Trenne Suchtext und zu durchsuchende Dateien
+ "\"" + os_escape(directory + "\\" + filemask) + "\""
+ "\"" // Ende Kommando
// Führe das Kommando aus ...
var oExec = WshShell.Exec(command);
// ... und gebe die Ausgabe (Kanal STDOUT, nicht STDERR) zurück
return oExec.StdOut.ReadAll();
}
/**
* Überprüft die Eingabeparameter.
* Aufruf ist wie folgt:
* Skriptname searchrow search replace directory logfile
* Folgende Prüfungen werden vorgenommen:
* Anzahl der Parameter muss 5 sein 32768
* searchrow - darf keinen Zeilenumbruch enthalten 32769
* search - muss in searchrow enthalten sein 32770
* replace - darf keinen Zeilenumbruch enthalten 32771
* directory - muss ein Verzeichnis sein 32772
* logfile - muss ein gültiger Dateipfad sein 32773
* Kein Fehler 0
* <b>check_input</b>
*
* @param {array} Liste der Aufrufparameter
* @return Errorcode
*/
function check_input(args) {
// Anzahl der Parameter muss 5 sein
if(args.length != 5) {
return 32768;
}
// im Text der Suchzeile darf kein Zeilenumbruch enthalten sein
if(args(0).indexOf("\n") != -1){
return 32769;
}
// der zu ersetzende Text muss in der Suchzeile enthalten sein
if(args(0).indexOf(args(1)) < 0){
return 32770;
}
// der neue Text darf keinen Zeilenumbruch enthalten
if(args(2).indexOf("\n") != -1){
return 32771;
}
// Prüfungen auf Verzeichnis und Datei benötigen ein FSO
var fso = new ActiveXObject("Scripting.FileSystemObject");
// Das angegebene Verzeichnis muss existieren
if (!fso.FolderExists(os_escape(args(3)))){
return 32772;
}
// Die angegebene Logdatei auch :-)
if (!fso.FileExists(os_escape(args(4)))){
return 32773;
}
return 0;
}
/*
* <b>main</b>
*/
function main(args, filemask, offset, recursive) {
// Überprüfe die Aufrufparameter des Skripts
var errorcode = check_input(args);
if (errorcode > 0) {
// Fehlerhafte Aufrufparameter
return(errorcode);
}
// Suche mit FINDSTR im angegebenen Verzeichnis in allen Dateien mit der
// angegebenen Dateiendung, ggf. auch in Unterverzeichnissen
var output = get_output_findstr(args(0), args(3), filemask, recursive);
// Filtere die Ausgabe, so dass nur noch die relevanten zweiten Zeilen
// jeder Datei übrigbleiben
output = filter_list(output);
// Durchlaufe die gefilterte Dateiliste:
var count = output.length;
for ( var i=0; i < count; i++){
var filename = os_escape(extract_filename(output[i]));
var line_no = extract_line_no(output[i]);
// Extrahiere den zu loggenden Text, Suchzeile plus folgende Zeilen (Anzahl = offset),
// und schreibe die geänderte Datei weg
var logged_text = process_file(filename, line_no, args(1), args(2), offset);
// Hänge den gewünschten Text an die Logdatei an
write_to_file(os_escape(args(4)), logged_text, 8);
}
return 0;
}
/**
* Nutze das Skript wie vorgesehen:
* Es werden HTML-Dateien durchsucht,
* Die Anzahl der ebenfalls zu loggenden Folgezeilen ist 19
* Unterverzeichnisse werden nicht durchsucht
*/
var args = WScript.Arguments;
var errorcode = main(args, "*.html", 19, false);
WScript.Echo(errorcode);
Freundliche Grüße Vinzenz