Come rilevare la fine della linea con sed


15

Sto cercando un modo per eseguire la sostituzione solo quando l'ultimo carattere è una nuova riga, usando sed.

Per esempio:

lettersAtEndOfLine

viene sostituito, ma questo non è:

lettersWithCharacterAfter&

Dal momento sedche non funziona bene con le nuove linee, non è così semplice

$ sed -E "s/[a-zA-Z]*\n/replace/" file.txt

Come può essere realizzato?

Risposte:


21

Con lo standard sed, non vedrai mai una nuova riga nel testo letto da un file. Questo perché sedlegge riga per riga e pertanto non esiste una nuova riga alla fine del testo della riga corrente nello sedspazio del modello. In altre parole, sedlegge i dati delimitati da newline e i delimitatori non fanno parte di ciò che sedvede uno script.

Le espressioni regolari possono essere ancorate alla fine della riga usando $(o all'inizio, usando ^). L'ancoraggio di un'espressione all'inizio / alla fine di una linea la costringe a corrispondere esattamente lì, e non solo in qualsiasi punto della linea.

Se vuoi sostituire qualcosa che corrisponda al motivo [A-Za-z]*alla fine della linea con qualcosa, quindi ancorando il motivo in questo modo:

[A-Za-z]*$

... lo costringerà a corrispondere alla fine della linea e in nessun altro posto.

Tuttavia, poiché non[A-Za-z]*$ corrisponde a nulla (ad esempio, la stringa vuota presente alla fine di ogni riga), è necessario forzare la corrispondenza di qualcosa , ad esempio specificando

[A-Za-z][A-Za-z]*$

o

[A-Za-z]\{1,\}$

Quindi, la tua riga di comando sed sarà così

$ sed 's/[A-Za-z]\{1,\}$/replace/' file.txt

Non ho usato l' -Einterruttore qui perché non è necessario. Con esso, avresti potuto scrivere

$ sed -E 's/[A-Za-z]+$/replace/' file.txt

È una questione di gusti.


I commenti non sono per una discussione estesa; questa conversazione è stata spostata in chat .
Kusalananda

3
sed "s/[a-zA-Z]*$/replace/" input.txt > result.txt

Oppure, il lungo modo inutile complesso:

Ho scoperto, questo può essere fatto, usando ancora sed, con l'aiuto di tr. Puoi assegnare un altro personaggio per rappresentare la fine della linea. È necessario utilizzare un altro carattere temporaneo, in questo caso "` ". Usiamo "~" per rappresentare la fine della linea:

tr '\n' '`' <input.txt >output.txt
sed -i "s/`/~`/" output.txt
tr '`' '\n' <output.txt >result.txt

E quindi per eseguire la ricerca effettiva e sostituire, utilizzare "~" anziché "\ n":

sed -i -E "s/[a-zA-Z]*~/replace/" result.txt

E poi ripulisci il carattere extra sulle altre linee:

sed -i "s/~//" result.txt

Ovviamente, tutto ciò può essere convogliato insieme dando origine a qualcosa del tipo:

tr '\n' '`' <input.txt | sed -e "s/`/~`/" | tr '`' '\n' | sed -E -e "s/[a-zA-Z]*~/replace/" | sed "s/~//" > result.txt

3
Non sono sicuro di aver capito ... Perché non ti limiti alla fine della linea $? ad es.s/[a-zA-Z]*$/replace/
don_crissti,

1
2 punti: 1) Faresti meglio a usare \+invece che *poiché quest'ultimo consente zero lettere alla fine della stringa; 2) È possibile utilizzare una classe di caratteri [[:alpha:]]. Quindi:sed 's/[[:alpha:]]\+$/replace/' file
Glenn Jackman,

@glennjackman Qual è la barra rovesciata prima del plus? Non corrisponderebbe al personaggio aggiuntivo?
Matthew D. Scholefield il

1
GNU sed senza l' -ropzione usa questa sintassi delle espressioni regolari .
Glenn Jackman,

0

Dallo snippet di codice (rotto) che hai pubblicato, sembra che desideri sostituire anche la nuova riga. In tal caso, l'ancoraggio regex da solo non può aiutarti. Di seguito è una soluzione:

sed '/[[:alpha:]]\+$/{N;s/[[:alpha:]]\+\n/replace/}' your_file

Suddiviso:

  • /[a-zA-Z]\+$/{} significa applicare tutto ciò che viene all'interno dei ricci alle linee che corrispondono alla regex.
  • Il regex è quello che usa l'ancoraggio come visto nella tua risposta , modificato per tenere conto dei commenti di Glenn Jackman .
  • All'interno dei ricci, Nsignifica "aggiungi la riga successiva al buffer attivo" (ciò che sedchiama lo "spazio modello")
  • Infine, la s///dichiarazione è la sostituzione richiesta. Ora funziona perché lo spazio del motivo contiene due righe successive e la newline ne fa quindi parte.

0

Per trovare la fine della riga, basta usare $ -sign :

Senza ancoraggio di fine linea:

sed -n '/pattern/p' file 

Senza ancoraggio di fine linea:

sed -n '/pattern$/p' file
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.