2016-03-27 12 views
0

Kennen Sie eine bessere oder einfachere Art und Weise, sed oder Bash zu verwenden, um vom letzten Auftreten einer Regex-Übereinstimmung vom Ende einer Zeile zu ersetzen, ohne rev zu verwenden?Ersetzen von Nth Auftreten vom Ende der Linie über Sed

Hier ist der rev Weg, um den dritter von den letzten Auftreten des Buchstabe ‚s‘ – noch nach vorn passend zu entsprechen, noch rev aus dem letzten Zeichen zu verwenden.

echo "a declaration of sovereignty need no witness" | rev | sed 's/s/S/3' | rev 
a declaration of Sovereignty need no witness 

aktualisieren - eine verallgemeinerte Lösung auf Basis von Cyruses Antwort:

SEARCH="one" 
OCCURRENCE=3 
REPLACE="FOUR" 
SED_DELIM=$'\001' 
SEARCHNEG=$(sed 's/./[^&]*/g' <<< "${SEARCH}") 
sed -r "s${SED_DELIM}${SEARCH}((${SEARCHNEG}${SEARCH}){$((${OCCURRENCE}-1))}${SEARCHNEG})\$${SED_DELIM}${REPLACE}\1${SED_DELIM}" <<< "one one two two one one three three one one" 

Hinweis: Um wirklich generisch sein es regex Elemente aus der LHS entkommen sollte.

+0

Bitte nehmen Sie sich einen Blick auf [Bearbeitungshilfe] (http://stackoverflow.com/editing-help). – Cyrus

Antwort

0

Mit GNU sed:

sed -r 's/s(([^s]*s){2}[^s]*)$/S\1/' file 

Ausgang:

 
a declaration of Sovereignty need no witness 

See: The Stack Overflow Regular Expressions FAQ

+0

Danke, das funktioniert für den einzelnen Buchstaben, den ich als Beispiel verwendet habe, aber für ein Wort regex '[^ s]' -> '[^ wichtigword]' wird nicht wie erwartet übereinstimmen. Das Zurücksetzen des Endankers ist ein Konzept, das funktioniert. –

+0

Um ein 'wichtigword' zu vergleichen, reduzieren Sie zuerst das genannte Wort auf ein eindeutiges einzelnes Zeichen, passen Sie dann wie oben an und setzen Sie dann die unveränderten Wörter wieder ein. – potong

0

Mit awk:

str='a declaration of sovereignty need no witness' 

awk -v r='S' -v n=3 'BEGIN{FS=OFS="s"} { 
    for (i=1; i<=NF; i++) printf "%s%s", $i, (i<NF)?(i==NF-n?r:OFS):ORS}' <<< "$str" 

Ausgang:

a declaration of Sovereignty need no witness 
0

Als erstes müssen Sie die Anzahl der Vorkommen zählen und die man herausfinden, ersetzen:

echo "importantword1 importantword2 importantword3 importantword4 importantword5 importantword6" | 
    grep -o "importantword" | wc -l 

verwenden, die für Ihre sed Zeichenfolge

echo "importantword1 importantword2 importantword3 importantword4 importantword5 importantword6" | 
    sed 's/\(\(.*importantword.*\)\{3\}\)importantword\(\(.*importantword.*\)\{2\}\)/\1ExportAntword\3/' 
importantword1 importantword2 importantword3 ExportAntword4 importantword5 importantword6 

Sie erhalten die gleiche Antwort mit den Einstellvariablen für links und rechts:

l=3 
r=2 
echo "importantword1 importantword2 importantword3 importantword4 importantword5 importantword6" | 
    sed 's/\(\(.*importantword.*\)\{'$l'\}\)importantword\(\(.*importantword.*\)\{'$r'\}\)/\1ExportAntword\3/' 

oder

str="\(.*importantword.*\)" 
echo "importantword1 importantword2 importantword3 importantword4 importantword5 importantword6" | 
    sed 's/\('${str}'\{'$l'\}\)importantword\('${str}'\{'$r'\}\)/\1ExportAntword\3/'