sed spaltenweise bearbeiten ohne awk?

C

Chib

Jungspund
Folgendes Problem: Ich habe eine Tabelle, welches in mehreren Spalten unterteilt ist (spaltentrennzeichen ist ein Pipezeichen "|"). In der 8. und 9. Spalten sine jeweils nur Nummer vorhanden. Ich will jetzt dass diese Nummer durch "Bezeichnungen" ersetzt werden (z.b 1=high, 2=middle, 3=low). Das Problem ist nun, dass in den beiden Spalten die Bezeichnungen anders sind -> d.h: in der 8.Spalte heisst Zahl 1 = High und in der 9.Spalte die Zahl 1 = Minor. Ich kann hier also kein sed global substitute machen.
Es ist auch nicht möglich von vorne die Anzahl Stellen zählen bis zur 8. und 9.Spalten und dann ein sed befehl einzusetzen, da sie von Zeile zu Zeile anders ist.
Ist es eigentlich nun möglich im sed statt zeilenweise vorzugehen, spaltenweise vorzugehen?
 
Spontan:
Code:
sed 's/\(|.*|.*|.*|\)1\(|.*|.*|\)/\1high\2/g'
macht aus
Code:
|1|2|1|2|1|2|1|
Code:
|1|2|1|2|high|2|1|
Gibt bestimmt elegantere Lösungen...
Gruss
d22
 
woher weisst du ob 1= high oder minor werden soll?
gibt es da irgentein identifyer?
 
das habe ich oben vergssen zu erwähnen.... in der 8.spalte soll es folgendes aussehen:

1=highest
2=high
3=normal
4=low

und der 9.spalte soll es so aussehen:

1=major
2=normal
3=minor
 
Hi,

mit sed in einer bestimmten Spalte mehrere Möglichkeiten zu supstitutionieren erscheint mir sehr schwierig bzw. absolut umständlich.
In awk eigentlich genauso - die gensub-Funktion hilft hier vielleicht ein wenig, aber spätestens bei der Ersetzung mehrerer Möglichkeiten wird es hier zu umständlich.

Da würde ich eher noch auf die gute alte while-read-Methode zurückgreifen:
Code:
#!/bin/bash
inputfile=$1
if [ ! -r "$inputfile" ]; then echo "Quelldatei nicht lesbar/existent!"; exit 1; fi
oldIFS=$IFS
IFS=\|
while read s1 s2 s3 s4 s5 s6 s7 s8 s9 rest; do
 case "$s8" in
  1) s8="highest";;
  2) s8="high";;
  3) s8="normal";;
  4) s8="low";;
 esac
 case "$s9" in
  1) s9="major";;
  2) s9="normal";;
  3) s9="minor";;
 esac
echo "$s1|$s2|$s3|$s4|$s5|$s6|$s7|$s8|$s9|$rest"
done < "$inputfile"
IFS=$oldIFS

Gruß Daniel
 
Zuletzt bearbeitet:
@fallout: bei deinem script zeigt er mir zwar keine fehler an aber er ändert auch nichts...
 
Zuletzt bearbeitet:
@fallout: bei deinem script zeigt er mir zwar keine fehler an aber er ändert auch nichts...

Hm, kurzer Test (unter GNU bash, version 3.1.17(1)-release):

fallout@server:~$ cat infile
1|2|3|4|5|6|7|1|2

fallout@server:~$ ./modifiy.sh infile
1|2|3|4|5|6|7|highest|normal|

Scheint soweit wie gewollt zu funktionieren. Ist vielleicht mal wieder eine Kompatibilitätsfrage - welche Shell verwendest Du?
Wenn dies bei Dir nichts verändert, liegt es vermutlich an einer fehlerhaften Trennung der Segmente durch das Pipe-Zeichen.
Versuche evtl. auch mal, den IFS mit IFS='|' zu setzen - vielleicht mag Deine Shell die Entwertung mit dem Backslash nicht.

Ggf. werden die case-Auswertungen auch nicht richtig als Strings interpretiert. Wandle diese mal in "1") s8="highest";; usw. um.

Gruß Daniel
 
nun ich verwende die Bash-shell 2.05 -> ich update es mal auf die neuste Verison und schaue dann wie es funktioniert

Edit: wenn ich denn script laufen lasse erscheint nur folgendens:

1|2|3|4|5|6|7|1|2|||||||||||
 
Zuletzt bearbeitet:
Rufst Du es auch mit dem Dateinamen als erstem Argument auf? Kannst Du ansonsten mal ein paar Zeilen aus der Datei senden?

jo hier:

langer text |ID2 |user1 |user2 |bg |08-may-2001 |closed | 3|1 |string_tab:68 |string_tab:69 |string_tab:70
also nun sollte die 8 (zahl 3 im Beispiel) und 9 (zahl 1 im Beispiel) Spalte geändert werden wie oben beschrieben

ps: sry für doppelpost :O
 
Hi,

langer text |ID2 |user1 |user2 |bg |08-may-2001 |closed | 3|1 |string_tab:68 |string_tab:69 |string_tab:70

Die zu ändernden Werte müssen für das genannte Skript schon eindeutig definiert sein.
Da das Pipe den Feldtrenner darstellt, werden Blanks natürlich mit in die zerlegten Strings gepackt. Dadurch schlägt der Vergleich dieses Wertes " 3" mit der Referenz "3" fehl.
Du kannst für den case-Vergleichsstring auch mehrere Alternativen angeben:
Code:
 case $variable in "3"|" 3"|"3 ") echo "Treffer";; esac
Mir ist leider nur nicht bekannt, daß case auch volle reguläre Ausdrücke unterstützt, sondern nur die Pfadnamenerweiterung (siehe man bash -> Pathname Expansion), welche nicht besonders felxibel ist.
Du könntest auch
Code:
 case $variable in *3*) echo "Treffer";; esac
einsetzen, wodurch jedoch sämtliche Spalten die irgendwo eine 3 enthalten geändert würden.

Edit:

Noch eine Alternative: Du kannst den zu vergleichenden String vor der Übergabe an case auch verändern/zurechtstutzen:
Code:
case $(echo "$variable" | sed 's/ //g') in 3) echo "Treffer";; esac
Dadurch wird der String nicht in seinem ursprünglichen Zustand an case übergeben, sondern vorher bearbeitet indem mit Hilfe von sed alle Blanks entfernt werden.

Gruß Daniel
 
Zuletzt bearbeitet:
Mir ist leider nur nicht bekannt, daß case auch volle reguläre Ausdrücke unterstützt, sondern nur die Pfadnamenerweiterung (siehe man bash -> Pathname Expansion), welche nicht besonders felxibel ist.
Mir auch nicht, aber man könnte das Ganze trotzdem meiner Meinung nach noch etwas verfeinern und zwar mit expr:
Code:
schlaubi:~ schlaubi$ var=" "; [b]variable="3"[/b]; case $variable in *3*) var="$(expr "$variable" : '^[0-9]$')" && echo "Treffer" || { echo "Wert '$variable' nicht eindeutig."; } ;; esac;
Treffer
schlaubi:~ schlaubi$ var=" "; [b]variable=" 3"[/b]; case $variable in *3*) var="$(expr "$variable" : '^[0-9]$')" && echo "Treffer" || { echo "Wert '$variable' nicht eindeutig."; } ;; esac;
Wert ' 3' nicht eindeutig.
 

Ähnliche Themen

suchen und ersetzen, Format erhalten

awk oder sed, textmanipulation

Zurück
Oben