2012-04-02 24 views
9

echo ddayaynightday | sed 's/day//g'Sed sostituto ricorsivamente

Finisce daynight

Esiste un modo per farlo sostituire fino a quando non è più partita?

+0

Ripetere fino a quando la sua lunghezza non cambia più. Non so, come farlo nella shell. – kirilloid

risposta

17

mio modulo preferito, per questo caso:

echo ddayaynightday | sed -e ':loop' -e 's/day//g' -e 't loop' 

Questo è lo stesso di tutti gli altri, se non che utilizza i comandi -e più per rendere le tre linee e utilizza il costrutto t, che significa "diramazione se si è eseguita correttamente la sostituzione", per eseguire l'iterazione.

+1

Buono a sapersi inserire più righe di script sulla riga di comando nei casi in cui ";" non funzionerà Preferirei la tua risposta anche a causa del salto condizionale 't' che è più chiaro per me, al contrario di un pattern match con salto incondizionato. –

+0

grazie :) penso che questo sembra buono, non sono sicuro se c'è un modo migliore di utilizzare alcuni regolari regolari ex .. – w00d

3

La bandiera g deliberatamente non corrisponde nuovamente alla parte sostituita della stringa. Quello che devi fare è un po 'diverso. Prova questo:

echo ddayaynightday | sed $':begin\n/day/{ s///; bbegin\n}' 

Grazie alla eccentricità di BSD Sed sono richiesti i ritorni a capo incorporati. Se stai usando GNU Sed si può essere in grado di cavarsela con

sed ':begin;/day/{ s///; bbegin }' 
+0

Nelle shell sh-like è anche possibile inserire una nuova riga letterale all'interno di una stringa quotata. D'altra parte trovo il '$ '... stringa con escapes ...'' costruisco più carino per script brevi come questo comunque. Per script veramente lunghi, usare '-f file' è probabilmente meglio. In questo caso particolare, funzionano anche molti comandi '-e'. – torek

+0

@torek: buon punto sui molteplici comandi '-e'. Personalmente odio incorporare le newline in una stringa quotata. È in genere più difficile da leggere e rende molto più difficile condividere il comando con altre persone (poiché in genere i comandi dovrebbero trovarsi su un'unica riga). –

+0

grazie, il tuo secondo non funziona sul mio osx, è sufficiente stampare l'input – w00d

1

le seguenti opere:

$ echo ddayaynightday | sed ':loop;/day/{s///g;b loop}' 
night 

A seconda del sistema, il ; potrebbe non funzionare per separare i comandi, in modo da poter utilizzare il seguente invece:

echo ddayaynightday | sed -e ':loop' -e '/day/{s///g 
               b loop}' 

Spiegazione:

:loop  # Create the label 'loop' 
/day/{  # if the pattern space matches 'day' 
    s///g  # remove all occurrence of 'day' from the pattern space 
    b loop # go back to the label 'loop' 
} 

Se la porzione del comando b loop non viene eseguita, i contenuti correnti dello spazio modello vengono stampati e viene letta la riga successiva.

+0

Neat, amico!321 – Almo

+0

Questo non funziona per me. Dà un errore: 'sed: 1:": loop;/day/{s/day // g; b ... ": etichetta inutilizzata 'loop;/day/{s/day // g; b loop} '' – Graham

+0

Il punto e virgola funziona solo in alcune versioni di sed. – torek

0

Ok, eccoli: while e strlen in bash. Il loro utilizzo si può realizzare la mia idea:

Repeat until its length will stop changing.

C'è né modo per impostare la bandiera né modo di scrivere come regex, a "sostituto fino a quando non più match".

5

Questo potrebbe funzionare per voi:

echo ddayaynightday | sed ':a;s/day//g;ta' 
night 
+0

non funziona sul mio osx – w00d

+0

Sembra che siano necessari più switch '-e' – potong

+0

Funziona * su * sul mio OSX 10.6.8 – MASL

2

con bash:

str=ddayaynightday 
while true; do tmp=${str//day/}; [[ $tmp = $str ]] && break; str=$tmp; done 
echo $str 
Problemi correlati