ubuntuusers.de

Zeile die eine bestimmte Zeichenkette enthält überspringen

Status: Gelöst | Ubuntu-Version: Ubuntu 10.04 (Lucid Lynx)
Antworten |

deXXteR275

Avatar von deXXteR275

Anmeldungsdatum:
7. Juni 2013

Beiträge: 46

Wohnort: Bad Hersfeld

Hallo zusammmen.

Ich habe ein Skript bei dem ich bestimmte Zeilen angebe und diese dann in einer Datei auskommentiert.

Da es aber auch vorkommt dass in der Textdatei Zeilen sind die nur ein "##" oder "###" enthalten schreibt das Skript vor diese Zeilen noch ein "##".

Angenommen ich gebe als Zeile 4-9 an, kommentiert das Skript Zeile 4,5,6,7,8 und 9 aus. Zeile 6 enthält aber einen Text ( ## bzw. ###) der nicht auskommentiert werden muss. Wie lautet also der Befehl im Skript damit er diese Zeile überspringt?

Ich habe egrep -v '^##$' dateiname gefunden aber das gibt mir ja nur die Zeile aus die am Satzanfang bis Satzende "##" enthält.

track

Avatar von track

Anmeldungsdatum:
26. Juni 2008

Beiträge: 7174

Wohnort: Wolfen (S-A)

Das klingt ziemlich kompliziert und doppelt-gewickelt ... 😲

Zeigst Du mal bitte Dein Skript und ein typisches Beispiel, was das korrekterweise machen soll ("vorher - nachher") ?
Es kommt ja drauf an, wie Du die Geschichte überhaupt anpackst ...

track

deXXteR275

(Themenstarter)
Avatar von deXXteR275

Anmeldungsdatum:
7. Juni 2013

Beiträge: 46

Wohnort: Bad Hersfeld

Das komplette Skript darf ich leider nicht posten, von daher nehme ich nur Ausschnitte die relevant sind. Ich starte das Skript; es fragt mich eine Anzahl ab (nehmen wir als Beispiel 3); dann kommt 3 mal hintereieinander eine Eingabeaufforderung wo ich jeweiles Zeilen angeben muss; bei jeder Anforderung für eine Eingabe gebe ich eine Zeilenangabe an (zum Beispiel: 1, 3-5, 7); dann werden vom Skript die Zeilen 1, 3, 4, 5 und 7 auskommentiert also vor jede Zeile ein ## gesetzt. In der Datei wo die Zeilen auskommentiert werden sollen gibt es zwischen den Zeilen Leerzeilen die nur ein ## oder ein ### enthalten.

Sprich vorher:

  1. texttexttexttexttexttext

  2. texttexttexttexttexttext

  3. ###

  4. texttexttexttexttexttext

  5. texttexttexttexttexttext

  6. ##

  7. texttexttexttexttexttext

Sprich nachher:

  1. ##texttexttexttexttexttext

  2. texttexttexttexttexttext

  3. ##### ⇒ dabei soll diese Zeile die vorher ### und jetzt ##### heißt übersprungen werden

  4. ##texttexttexttexttexttext

  5. ##texttexttexttexttexttext

  6. ##

  7. ##texttexttexttexttexttext

 while [ $zahl1 != $zahl2 ]
do
sed -i -e "$zahl1 s/^/##/" $dateiname
((zahl1 = $zahl1 + 1))
done

Zahl1 wäre jetzt die Zahl 3 und Zahl2 wäre die Zahl 5. Also kommentiert diese Schleife Zeile 3-5 aus. Verständlich erklärt?

Nun soll er aber nicht die Zeile 3 auskommentieren sondern überspringen weil diese Zeile ja bereits auskommentiert ist.

Ich weiß nicht wie ich besser erklären soll...

track

Avatar von track

Anmeldungsdatum:
26. Juni 2008

Beiträge: 7174

Wohnort: Wolfen (S-A)

Sowas mit einer while- Schleife zu machen ist aber ziemlich umständlich ! - das kann sed doch gleich in einem Rutsch erledigen:

  1. Du bastelst den Befehl für sed einfach vorab aus Deinen Eingaben und dem Ersetzungsblock zusammen.

    1. Der Ersetzungsblock könnte z.B. sowas sein: s/^[^#][^#]/##&/
      ("ersetze alles was nicht mit ## beginnt durch sich selbst mit 2x # davor")

    2. Das musst Du natürlich für jede Zeilenadresse einzeln dahinter schreiben:
      sed "1 s/^[^#][^#]/##&/; 3,5 s/^[^#][^#]/##&/; 7 s/^[^#][^#]/##&/;"

  2. Um diesen sed- Befehl für die vorgegebenen Zeilenzahlen zusammenzusetzen, kannst Du sehr gut eine Parameter Expansion verwenden:

    track@lucid:~$ z="1 3,5 7 "
    track@lucid:~$ echo "${z// / s/^[^#][^#]/##&/; }"
    1 s/^[^#][^#]/##&/; 3,5 s/^[^#][^#]/##&/; 7 s/^[^#][^#]/##&/;  

Probeweise liefert das bei mir:

track@lucid:~$ echo '1texttexttexttexttexttext
2texttexttexttexttexttext
###
4texttexttexttexttexttext
5texttexttexttexttexttext
##
7texttexttexttexttexttext
8texttexttexttexttexttext
###
10texttexttexttexttexttext
11texttexttexttexttexttext
##'  |  sed  "1 s/^[^#][^#]/##&/; 3,5 s/^[^#][^#]/##&/; 7 s/^[^#][^#]/##&/;"
##1texttexttexttexttexttext
2texttexttexttexttexttext
###
##4texttexttexttexttexttext
##5texttexttexttexttexttext
##
##7texttexttexttexttexttext
8texttexttexttexttexttext
###
10texttexttexttexttexttext
11texttexttexttexttexttext
## 

Das ist doch ungefähr was Du wolltest ?

LG,

track

wxpte

Anmeldungsdatum:
20. Januar 2007

Beiträge: 1388

deXXteR275 schrieb:

Ich habe egrep -v '^##$' dateiname gefunden aber das gibt mir ja nur die Zeile aus die am Satzanfang bis Satzende "##" enthält.

Das ist klar, weil der Ausdruck keinen Quantoren enthält. Bei egrep -v "^##+$" werden auch Zeilen erfasst, die mehr als zwei Rauten enthalten.

deXXteR275

(Themenstarter)
Avatar von deXXteR275

Anmeldungsdatum:
7. Juni 2013

Beiträge: 46

Wohnort: Bad Hersfeld

Hey,

erstmal Danke für deine Antwort ich werde es gleich mal ausprobieren. Natürlich ist es umständlich aber ich kanns noch nicht anders ^^ mach das jetzt seit ca 2 Monaten an der Arbeit und den Großteil habe ich mir selbst beigebracht und dann komplizierte sed-Anweisungen zusammen zubasteln ist noch zu hoch für mich ^^

Ob es das ist weiß ich nicht ich muss mir den Text nochmal genau durchlesen 😀

deXXteR275

(Themenstarter)
Avatar von deXXteR275

Anmeldungsdatum:
7. Juni 2013

Beiträge: 46

Wohnort: Bad Hersfeld

WinXP to Edgy schrieb:

Das ist klar, weil der Ausdruck keinen Quantoren enthält. Bei egrep -v "^##+$" werden auch Zeilen erfasst, die mehr als zwei Rauten enthalten.

Vollkommen richtig habe ich verwechselt.

deXXteR275

(Themenstarter)
Avatar von deXXteR275

Anmeldungsdatum:
7. Juni 2013

Beiträge: 46

Wohnort: Bad Hersfeld

Also wenn ich

sed "2 s/^[^#][^#]/##&/;" dateiname.txt

eingebe passiert gar nichts. Egal ob in Zeile 2: ##, ###, #### oder gar nichts steht.

Ich habe versucht:

while read stream 
do		
((i=$i+1))		
z=`echo ${field[b]}`		
if [ -n "$z" ]
then				
if [ $i -eq $z ]
then
raute=$(echo $stream | sed '/^##$/!d')
if [ -z "$raute" ]
then
sed -i -e "$i s/^/##/" $dateiname
((b=$b+1))
else 
((b=$b+1))
fi				
else 
((z=$z+1))
fi
fi

done < $dateiname

Sprich er überprüft dann jede einzelne Zeile ob die mit ## beginnt und endet. Aber wenn ich dann die Variable raute gefüllt ist (-n) dann dürfte er gar nicht in den Zweig reinkommen wo er die ## vor die Zeile setzt. Er geht trotzdem in den Ja-Zweig der IF-Anweisung obwohl die Variable raute gefüllt ist.

deXXteR275

(Themenstarter)
Avatar von deXXteR275

Anmeldungsdatum:
7. Juni 2013

Beiträge: 46

Wohnort: Bad Hersfeld

nach vielem rumprobieren habe ich es hinbekommen ☺))

while read stream
do
((j=$j+1))
raute=$(echo $stream | sed '/^##$/!d')

if [ -n "$raute" ]
then
array[x]=$j
((x=$x+1))
fi

done < $dateiname

Array genommen dass den Wert speichert in der Zeile j wenn Variable raute gefüllt ist ☺

track

Avatar von track

Anmeldungsdatum:
26. Juni 2008

Beiträge: 7174

Wohnort: Wolfen (S-A)

deXXteR275 schrieb:

Also wenn ich

sed "2 s/^[^#][^#]/##&/;" dateiname.txt

eingebe passiert gar nichts. Egal ob in Zeile 2: ##, ###, #### oder gar nichts steht.

Das war doch die Absicht, oder nicht ?
Wenn die Zeile ihre zwei oder mehr ## vorne hat, soll sie nicht verändert werden. Oder habe ich das falsch verstanden ?

Das was Du mit Deinem Shellskript mühsam zusammenbastelst, dafür ist sed von Haus aus gemacht: nämlich Zeilen erkennen und bearbeiten.
Mein Einzeiler ersetzt Dein ganzes Skript ! - kurz erklärt:

sed  "2 s/^[^#][^#]/##&/'
      ^ ^ ^ ^^  ^^  ^^^
      | | | |   |   | \ und das gesuchte Muster
      | | | |   |   \ durch zwei Rauten ...
      | | | \---\ 2x "keine Raute" steht:
      | | \ am Zeilenanfang ...
      | \ ersetze, wenn
      \ In Zeile 2

LG,

track

Antworten |