PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : find and replace



der_hai
22-09-2007, 15:24
Hallo!
Ich habe folgendes Problem:

In einer Skriptdatei finden sich verschiedenen einmalige Werte die durch andere einmalige Werte aus einer externen Datei ersetzt werden müssen.
-----------------------------------------------------------------------------------------------
beispiel datei 1:
exec createAccount
@user_id
@accounts_id
-----------------------------------------------------------------------------------------------
Parallel gibt es dazu eine tabstop getrennte Listendatei

Beispiel: datei 2
@user_id = 1,
@accounts_id = 1,
-----------------------------------------------------------------------------------------------
Jetzt suche ich eine Möglichkeit automatisiert über die Unix Shell jeweils die Listendatei abarbeiten zu lassen und dann die parameter(z.B @user_id) in der Skirpt Datei1 immer durch den neuen Wert der skript datei 2 zu ersetzen.

Der Ablauf ist mir klar nur leider fehlt mir bei der Umsetzung das spezifische Unix Wissen um die richtigen Paramenter und Befehle dafür zu finden.

Ablauf:

- > datei 1 wird eingelesen
- > Erster parameter "@user_id" wird eingelesen
- > @user-id wird in der Datei 2 gesucht(suchkriterium ist das @,erstmal wird nach @ gesucht und dann mit den parametern verglichen), falls es gefunden wird, wird das was hinter dem gleichheitszeichen steht kopiert,und ersetzt die variable @user_id in der skriptdatei 1
- > und so gehts weiter mit dem zweiten parameter "@accounts_id" usw...

Usw....
der grundgedanke ist letztendlich, dass der wert von @user_id aud datei 2 den parameter @user-id aus datei 1 ersetzt.

Jemand Ideen mit welchen Befehlen/Systemprogramen man das umsetzen kann?

Danke im vorraus für Eure Hilfe....

jan61
23-09-2007, 13:33
Moin,

irgendwie komme ich mit Deinen Erklärungen nicht klar:

1. In Deinem Beispiel für datei2 sehe ich keine Tabstops. Sieht datei2 so aus, wie in Deinem Beispiel?
2. Werden in datei2 mehrere solcher @user_id / @accounts_id-Wertepaare geliefert?
3. Wenn ja: Soll für jeden dieser Werte eine neue Substitution in datei1 vorgenommen werden?

Abhängig davon gibt es verschiedene Lösungsansätze (read-Schleife, awk, perl, ...).

Jan

BLUESCREEN3D
23-09-2007, 14:27
4. Stehen in Datei 2 nur Zahlen?
5. Steht wirklich hinter jedem Wert (also auch hinter dem letzten) ein Komma?
6. Aus welchen Zeichen können sich die Namen hinter dem @ zusammensetzen?

Falls du noch ein Dateibeispiel postest, benutz bitte das [code]-Tag.

der_hai
26-09-2007, 23:12
Zu 1, die datei sieht genauso aus wie in meinem beispiel
Zu 2, in datei 2 werden mehrere solcher @user_id geliefert, deshalb ist das mit einer schleife leichter zu handhaben,
weil
1) sie alle erst mal verglichen werden müssen(die von datei 1 mit datei 2)
2) die reihenfolge wird nicht zwingend eingehalten,deshalb ist eine schleife zum vergleichen notwendig, sonst stehen am ende falsche werte.
und dann werden die werte ersetzt.

Vergleichen ist eigentlich leicht, da die @ als suchkriterium dient, Z.b. wird in datei 1 nach dem ersten @ geguckt, dann wird das gleiche in datei 2 gesucht, falls vorhanden ist, wird Z.b. @user_id durch den wert(in datei2) in datei1 ersetzt.

Zu 3, wie ich in nr 2 erklärt habe, solche @user-id werden von beiden dateien verglichen, und letztendlich wird die substitution in datei 1 vorgenommen.
Es ist vollkommen egal, ob es mit read-schleife,sed, awk, perl,....... umgesetzt wird, es müsste nur laufen :D, mit sed habe ich schon probiert (sed -i "s/{search}/{replace}/g"), aber leider habe ich nicht hingekriegt.
Zu 4, in datei 2 stehen immer variablen, gleichheitszeichen,und ihre werte
@user_id = 1
@accounts_id = 1
@name = nicola
@vorname = nikolaus
@semestre = 4
…. Usw

Zu 5, die kommas stehen eigentlich gar nicht da, ich habe sie nur zum besseren verständnis hinzugefügt
Zu 6, die zeichen hinter dem komma sind entweder Strings oder zahlen, mehr gibt’s es net.

Hier ein beispiel von mir:
For zeile in $(cat $datei2)
Do
Search=$(echo $zeile | cut –d "=" –f 1)
replace=$echo $zeile | cut –d "=" –f 2)
sed -i "s/${search}/${replace}/g" $datei1
done

vielleicht hilft ein bisschen weiter.

Vielen dank im voarraus

jan61
27-09-2007, 19:17
Moin,

sorry, wenn ich penetrant wirke, aber um Dir helfen zu können, will ich noch ein wenig mehr wissen :rolleyes:

Der prinzipielle Aufbau von datei2 ist mir jetzt klar, also keine Tabstopps, sondern "@key = value"-Paare. Was mir noch unklar ist:
...Zu 2, in datei 2 werden mehrere solcher @user_id geliefert...
2) die reihenfolge wird nicht zwingend eingehalten...

Und da hakt es: Welche Reihenfolge wird nicht zwingend eingehalten? Wie soll aus mehreren Werten (z. B. für @user_id) in datei2 die Ersetzung in datei1 vorgenommen werden? Gibt es dafür jeweils einen zu ersetzenden Platzhalter in datei1 (also: finde erste @user_id in datei2 und ersetze mit dem Wert die 1. @user_id in datei1)?

Am einfachsten ist es, wenn Du erstmal nicht spekulierst, wie man wo eine Schleife machen müsste, sondern wenn Du uns konkret an aussagekräftigen Beispieldateien 1 + 2 zeigst, wie die Daten real aussehen und dann, wie das Ergebnis aussehen soll. Also auch mit Beispielen, wo eine Reihenfolge nicht eingehalten wird und bitte mit mehreren Sätzen (also @user_id, wie von Dir geschrieben).

Es ist einfacher, wenn Du nicht versuchst, alles in Prosa zu erklären, sondern wenn wir konkret sehen, wie das Ganze aufgebaut ist.

Jan

der_hai
01-10-2007, 16:21
Moin alle,
datei2: diese datei wird von der standardeingabe mit parametern und ihren werten gefüllt.
@user_id = 12345
@name = anders
@vorname = thomas
@telefon = 01234567
@handy = 0987654
@rolle = student
@semester= 4
----------------------------------------------------
Datei1: ist eine procedure die nachher ausgeführt werden sollte, wobei parameter übergeben werden,aber vorher müssen die parameter mit ihren jeweiligen werten gefüllt werden.

Exec procedure test
#jetzt kommen die parameter
@user_id
@name
@vorname
@telefon
@handy
@rolle
@semester
------------------------------------------------------

Die Ergebnisdatei :so sollte es am ende aussehen

Exec procedure test
#jetzt werden die werte übergeben
12345
anders
thomas
01234567
09876543
student
4
---------------------------------------------------------

Das habe ich vergessen zu erklären, aber du lagst zum teil richtig mit deiner vermutung,
Zitat:“Gibt es dafür jeweils einen zu ersetzenden Platzhalter in datei1 (also: finde erste @user_id in datei2 und ersetze mit dem Wert die 1. @user_id in datei1)?

Die parameter in datei1 sind sozusagen Platzhalter für die werte aus datei2, also finde @user_id in datei2 und ersetze mit dem wert die @user_id in datei1, aber nicht finde erste @user_id und ersetze mit dem wert die erste @user-id in datei1, da jeder user nur eine user_id haben kann, das reicht aus um ihn eindeutig zu identifizieren.

Ich stelle es mir mit der schleife so vor, dass man in datei 2 einen parameter oder wort (wie auch immer ;)) beginnend mit @ sucht, (@ ist das suchkriterium, Z.b. @user_id),hat man es gefunden, vergleicht man in datei 1 ob @user_id gibt, falls es vorhanden, wird die substitution in datei 1 vorgenommen.

Das ist ein contentmanagementsystem (CMS), und man müsste ein formular ausfüllen, um sich zu registrieren, und es gibt auch ein paar felder, die optional sind, aber es wäre nicht richtig, wenn man davon ausgeht, dass die reihenfolge immer die gleiche ist, weil es gibt einige parameter, die beim ausfüllen den wert null (optional) annehmen können, und so stehen sie gar nicht in datei 2(Z.b. handynummer),und das führt sonst dazu, dass am ende falsche werte zugewiesen werden.

Wenn du aber eine andere vorgehenweise hast, die am ende zum dem gleichen ergbnis führt, würde ich mich darauf freuen.
Danke nochmals

jan61
01-10-2007, 19:50
Moin,

hm, ich hoffe, jetzt habe ich alles richtig verstanden. So könnte man es z. B. machen:

jan@jack:~/tmp/dat1dat2> cat cre_proc.sh
awk -v tmpl=datei1 '
BEGIN { # Einlesen der datei1, die als Template fuer die Ausgabe dient
nr = 1;
while (getline l1 <tmpl) {
dat1[l1] = l1; # Array mit den Platzhaltern bzw. konstanten Werten
nr1[nr] = l1; # Zeilennummern-Array fuer Ausgabe
nr ++;
}
}
$1 ~ /^@/ { dat1[$1] = $3; # Inhalte aus datei2 ersetzen
}
END { # Ausgabe: Iterieren ueber Zeilennummern-Array
for (no = 1; no < nr; no++) {
# Inhalt aus datei1 nur dann ausgeben, wenn ersetzt
if (dat1[nr1[no]] !~ /^@/)
print dat1[nr1[no]];
# sonst: Leerstring ausgeben
else
print "";
}
} ' datei2
jan@jack:~/tmp/dat1dat2> ./cre_proc.sh
Exec procedure test
12345
anders

01234567
0987654
student
4
Da mir nicht ganz klar war, was bei @xxx passieren soll, die nicht in datei2 auftauchen, habe ich an den Stellen mal einen Leerstring ausgegeben (ich hatte in meinen Beispieldaten den Vornamen auskommentiert). Das Ganze ist noch nicht wasserdicht, weil z. B. in Datei immer der Aufbau "@key<Leer>=<Leer>wert" erwartet wird, das sollte man dann z. B. noch abfangen.

Jan

der_hai
04-10-2007, 21:03
hallo,

erstmal danke für die antwort, das bringt mich bestimmt weiter :D
ich habe aber noch zwei fragen,
1)wie würde das script aussehen, wenn in datei 2 die daten immer vollständig wären?
2)und wie würde das script aussehen, wenn statt "@key<Leer>=<Leer>wert" > "@key=wert" wäre, d.h. ohne leere felder?, da ich mir noch nicht sicher bin, ob der aufbau mit leeren feldern oder ohne ist. das müsste ich noch mit meinem betreuer absprechen, der ist aber leider in urlaub.
aber höchwahrscheinlich ist es ohne leere felder, gemäß unix-standards :eek:

danke

der_hai

jan61
07-10-2007, 11:12
...
1)wie würde das script aussehen, wenn in datei 2 die daten immer vollständig wären?
Nicht anders. Das Ersetzen durch Leerstrings wirkt ja nur, wenn der Wert für einen Schlüssel nicht geliefert wird. Wesentlich an dem awk-Script ist, dass er sowohl falsche Reihenfolgen als auch fehlende Werte behandeln kann, sie aber nicht zwingend erwartet.


2)und wie würde das script aussehen, wenn statt "@key<Leer>=<Leer>wert" > "@key=wert" wäre, d.h. ohne leere felder?...

Da gibt es verschiedene Varianten, z. B.:
a) Du gibst dem awk als Feldtrenner das "=" mit:
awk -F"=" -v ...musst dann aber innerhalb des awk-Scripts $2 statt $3 benutzen (Das Gleichheitszeichen ist dann nicht mehr Feldinhalt, sondern Begrenzer).
b) Du sorgst z. B. per sed dafür, dass Leerzeichen ergänzt werden:

sed 's/=/ = /' datei 2 | awk ...Dann sind sowohl Fälle mit als auch ohne Leerzeichen berücksichtigt (ob zwischen 2 Feldern 1 oder mehrere Blanks stehen, interessiert den awk nicht).


...
aber höchwahrscheinlich ist es ohne leere felder, gemäß unix-standards

Was meinst Du denn damit?

Jan