Wie kann ich alles bis zu einem Muster und alles nach einem anderen Muster aus einer Zeile löschen?

15

In der folgenden Datei:

Lorem ipsum dolor sitzt amet, consectetuer adipiscing elit. Ut eu metus id lectus vestibulum ultrices. Maecenas Rhoncus.

Ich möchte alles vorher consectetuerund alles nachher löschen elit.

Meine gewünschte Ausgabe:

consectetuer adipiscing elit.

Wie kann ich das machen?

manuel
quelle
2
Der Befehl kann sein sed. Es kann auch perloder sogar reine Bash sein.
muru
@manuel Wenn eine dieser Antworten Ihr Problem gelöst hat, nehmen Sie sich bitte einen Moment Zeit und akzeptieren Sie sie, indem Sie auf das Häkchen links klicken. Dadurch wird die Frage als beantwortet markiert und auf den Stack Exchange-Sites wird der Dank ausgesprochen.
Terdon

Antworten:

26

Ich würde sed benutzen

sed 's/^.*\(consectetuer.*elit\).*$/\1/' file

Dekodiert die sed s / find / replace / Syntax:

  • s/^.*- Ersetze beginnend am Anfang der Zeile ( ^) gefolgt von irgendetwas ( .*) bis ...
  • \( - einen benannten Block starten
  • consectetuer.*elit\.- Ordnen Sie das erste Wort zu, alles ( .*) bis zum letzten Wort (in diesem Fall einschließlich des abschließenden Punkts), mit dem Sie übereinstimmen möchten
  • \) - Beenden Sie den genannten Block
  • stelle alles andere ( .*) auf das Ende der Zeile ( $)
  • / - Beenden Sie die Ersatzsuche
  • \1- ersetzen mit dem Namen Block zwischen dem \(und dem \)oben
  • / - Ersetzen beenden
MikeV
quelle
1
Gute Antwort, aber Sie brauchen das ^oder nicht, $da sed versucht, die längste Übereinstimmung zu finden. Außerdem haben Sie möglicherweise den Punkt danach verpasst elit, den Sie \.bei Bedarf einfügen können.
Asoundmove
2
@asoundmove Guter Fang für den nachgestellten Punkt bei "elit". - Sie haben ein ziemlich scharfes Auge !. Ich habe meine Antwort aktualisiert, um den maskierten Punkt in das Muster aufzunehmen. Sie korrigieren auch, dass das ^und $nicht notwendig sind - ich habe sie dort gelassen, weil der Fragesteller (ursprünglich) bemerkt hat, dass er ein bisschen ein Anfänger war und dies in anderen Zusammenhängen hilfreich sein kann.
MikeV
6

Wenn jede Zeile sowohl Start- als auch Endmuster enthält, ist dies am einfachsten mit möglich grep. Anstatt den Anfang und das Ende jeder Zeile zu löschen , können Sie einfach den Inhalt zwischen beiden Mustern ausgeben. Die -oOption in GNU grepgibt nur die Übereinstimmungen aus:

grep -o 'consectetuer.*elit' file

Hinweis: Wie bereits erwähnt, funktioniert dies nur, wenn jede Zeile in der Datei auf diese Weise analysiert werden kann. Andererseits sind das 80% aller typischen Anwendungsfälle.

Slebetman
quelle
1

Zwei für Schleifen in AWK:

$ awk '{for(i=1;i<=NF;i++) {if ($i == "consectetuer") beginning=i; if($i== "elit.") ending=i }; for (j=beginning;j<=ending;j++) printf $j" ";printf "\n"   }' file.txt 
consectetuer adipiscing elit.

AWK's gsub:

$ awk '{gsub(/^.*consectetuer/,"consectetuer"); gsub(/elit.*$/,"elit.");print}' file.txt
consectetuer adipiscing elit.
Sergiy Kolodyazhnyy
quelle
1

Ein Perl Weg. Dies entspricht im Wesentlichen der Antwort von MikeVsed :

perl -pe 's/.*(consectetuer.*elit).*./$1/' file

Das -pbedeutet "drucke jede Zeile nach dem Anwenden des mit -e". Der s/foo/bar/ist der Substitutionsoperator; es wird ersetzt foodurch bar. Die Klammern erfassen ein Muster und lassen uns es als Ersatz verwenden. Das erste erfasste Muster ist $1das zweite $2und so weiter.

Der Befehl vergleicht also alles bis consectetuer( .*consectetuer), dann alles bis elit( .*elit) und dann alles andere bis zum Ende der Zeile ( .*) und ersetzt dies durch das erfasste Muster.

terdon
quelle
1

Ich bin nicht sicher, warum dieser Fragentitel " von Datei " zu " von einer Zeile " bearbeitet wurde, während das OP die Möglichkeit über mehrere Zeilen nicht ausschließt, obwohl das Beispiel nur eine Zeile zu sein scheint. Wie auch immer, es könnte hilfreich sein, hier eine Lösung mit mehreren Leitungen bereitzustellen.

Dies funktioniert für gekreuzte Linien:

from1=consectetuer; to2=elit; a="$(cat file)"; a="$(echo "${a#*"$from1"}")"; echo "$from1${a%%"$to2"*}$to2"

Beispiele:

[xiaobai@xiaobai tmp]$ cat file
1
abc consectetuer lsl

home

def elit dd
2 consectetuer ABC elit
[xiaobai@xiaobai tmp]$ from1=consectetuer; to2=elit; a="$(cat file)"; a="$(echo "${a#*"$from1"}")"; echo "$from1${a%%"$to2"*}$to2"
consectetuer lsl

home

def elit
[xiaobai@xiaobai tmp]$ 

Referenz: Shell-Parametererweiterung

林果 林果
quelle
1
Das ist perfekt!
Clément