Sostituisci l'intera riga contenente una stringa usando Sed


319

Ho un file di testo che ha una riga particolare simile

sometext sometext sometext TEXT_TO_BE_REPLACED sometext sometext sometext

Ho bisogno di sostituire l'intera riga sopra con

This line is removed by the admin.

La parola chiave di ricerca è TEXT_TO_BE_REPLACED

Ho bisogno di scrivere uno script di shell per questo. Come posso ottenere questo usando sed?


@Scharron Ho provato a sed -rne 's / (TEXT_TO_BE_REPLACED) \ s + \ w + / \ 1 yyy / xxx' Ma questo sostituirebbe yyy con xxx nella stringa se è presente uno yyy. Nel mio caso il testo non è stato risolto ... tutto quello che ho è TEXT_TO_BE_REPLACED.
Rahul,

questa non è un'espressione sed valida. Sei sicuro di volerlo con sed? Qualsiasi linguaggio di programmazione con buone regexps può sostituirti (cerca una sub funzione). Sarebbe più semplice che capire sed da soli
Scharron,

@Scharron Bene, lo si deve fare con lo script della shell, quindi immagino che sed sia la mia scommessa migliore.
Rahul,

Risposte:


483

È possibile utilizzare il comando change per sostituire l'intera riga e il -iflag per apportare le modifiche sul posto. Ad esempio, usando GNU sed:

sed -i '/TEXT_TO_BE_REPLACED/c\This line is removed by the admin.' /tmp/foo

4
Si noti che è necessario uno spazio prima di c \. Ho appena modificato per aggiungere questo.
Marcus Downing,

27
@MarcusDowning GNU sed non richiede spazio; funziona bene come pubblicato originariamente. Se la tua particolare sed richiede lo spazio, allora nota quale sed non è compatibile e aggiungi l'invocazione necessaria come commento. Tuttavia, non modificare il codice di lavoro in una risposta accettata.
Todd A. Jacobs,

7
Come posso usare una variabile al posto del testo "Questo ..."? Se lo sostituisco con $ variabile, non stampa il suo contenuto ma il nome della variabile.
Steven,

18
C'è un problema con c\ quando seguito direttamente da una variabile: …c\$VAR…la barra rovesciata sfuggirà al dollaro. In questo caso ho (bash / sed su Ubuntu 15.10) dovuto scrivere…c\\$VAR…
Jan

6
su un uso Mac: sed -i '' '/TEXT_TO_BE_REPLACED/c\This line is removed by the admin.' /tmp/foo; (quando il primo parametro è vuoto modifica in-file, altrimenti crea un backup)
AndreDurao

152

È necessario utilizzare i caratteri jolly ( .*) prima e dopo per sostituire l'intera riga:

sed 's/.*TEXT_TO_BE_REPLACED.*/This line is removed by the admin./'

Grazie, ho fatto funzionare il mio: sed 's /.* <espressione>. * / <espressione> SE_LABEL = ABC <espressione> / g' MYR2.xml> test.txt
Nasri Najib

9
Questo funziona su Mac OS X Yosemite con l'eccezione che sto usando i flag -i e -e come segue:sed -i -e "s/.*search_string.*/Replacement_line/' file_being_searched.txt
Kent Bull,

1
@KentJohnson Penso che tu abbia virgolette non corrispondenti nel tuo comando.
HashHazard,

@MBarnett hai ragione, dovrei avere due doppie virgolette lì.
Kent Bull,

2
Solo per le informazioni complete. Per renderlo operativo, è possibile aggiungere -iun'opzione
Temak,

20

La risposta accettata non ha funzionato per me per diversi motivi:

  • la mia versione di sed non piace -icon un'estensione di lunghezza zero
  • la sintassi del c\comando è strana e non sono riuscito a farlo funzionare
  • Non mi ero reso conto che alcuni dei miei problemi provenissero da barre senza caratteri di escape

Quindi ecco la soluzione che mi è venuta in mente e penso che dovrebbe funzionare nella maggior parte dei casi:

function escape_slashes {
    sed 's/\//\\\//g' 
}

function change_line {
    local OLD_LINE_PATTERN=$1; shift
    local NEW_LINE=$1; shift
    local FILE=$1

    local NEW=$(echo "${NEW_LINE}" | escape_slashes)
    sed -i .bak '/'"${OLD_LINE_PATTERN}"'/s/.*/'"${NEW}"'/' "${FILE}"
    mv "${FILE}.bak" /tmp/
}

Quindi l'utilizzo di esempio per risolvere il problema ha posto:

change_line "TEXT_TO_BE_REPLACED" "This line is removed by the admin." yourFile

18

La risposta sopra:

sed -i '/TEXT_TO_BE_REPLACED/c\This line is removed by the admin.' /tmp/foo

Funziona bene se la stringa / riga sostitutiva non è una variabile.

Il problema è che su Redhat 5 il \dopo csfugge al $. Neanche un doppio \\ha funzionato (almeno su Redhat 5).

Attraverso hit e trial, ho scoperto che il \dopo cè ridondante se la stringa / linea di sostituzione è solo una singola linea. Quindi non ho usato \dopo il c, ho usato una variabile come singola linea di sostituzione ed è stata una gioia.

Il codice sarebbe simile a:

sed -i "/TEXT_TO_BE_REPLACED/c $REPLACEMENT_TEXT_STRING" /tmp/foo

Nota l'uso di virgolette doppie anziché singole.


puoi ancora usare virgolette singole come questa: sed -i '/ TEXT_TO_BE_REPLACED / c' "$ VARIABLE" '' / tmp / foo
Alistair McIntyre

4

Tutte le risposte fornite finora presuppongono che tu sappia qualcosa sul testo da sostituire, il che ha senso, poiché è quello che l'OP ha chiesto. Sto fornendo una risposta che presuppone che tu non sappia nulla del testo da sostituire e che potrebbe esserci una riga separata nel file con lo stesso contenuto o simile che non desideri sostituire. Inoltre, presumo che tu conosca il numero di riga della riga da sostituire.

I seguenti esempi dimostrano la rimozione o la modifica del testo mediante numeri di riga specifici:

# replace line 17 with some replacement text and make changes in file (-i switch)
# the "-i" switch indicates that we want to change the file. Leave it out if you'd
#   just like to see the potential changes output to the terminal window.
# "17s" indicates that we're searching line 17
# ".*" indicates that we want to change the text of the entire line
# "REPLACEMENT-TEXT" is the new text to put on that line
# "PATH-TO-FILE" tells us what file to operate on
sed -i '17s/.*/REPLACEMENT-TEXT/' PATH-TO-FILE

# replace specific text on line 3
sed -i '3s/TEXT-TO-REPLACE/REPLACEMENT-TEXT/'

3

per manipolazione di file di configurazione

mi è venuta in mente questa soluzione ispirata alla risposta skensell

configLine [searchPattern] [replaceLine] [filePath]

lo farà:

  • crea il file se non esiste
  • sostituisce l'intera riga (tutte le righe) in cui searchPattern corrisponde
  • aggiungi replaceLine alla fine del file se il modello non è stato trovato

Funzione:

function configLine {
  local OLD_LINE_PATTERN=$1; shift
  local NEW_LINE=$1; shift
  local FILE=$1
  local NEW=$(echo "${NEW_LINE}" | sed 's/\//\\\//g')
  touch "${FILE}"
  sed -i '/'"${OLD_LINE_PATTERN}"'/{s/.*/'"${NEW}"'/;h};${x;/./{x;q100};x}' "${FILE}"
  if [[ $? -ne 100 ]] && [[ ${NEW_LINE} != '' ]]
  then
    echo "${NEW_LINE}" >> "${FILE}"
  fi
}

la folle magia dello stato di uscita proviene da https://stackoverflow.com/a/12145797/1262663


2
bash-4.1$ new_db_host="DB_HOSTNAME=good replaced with 122.334.567.90"
bash-4.1$ 
bash-4.1$ sed -i "/DB_HOST/c $new_db_host" test4sed
vim test4sed
'
'
'
DB_HOSTNAME=good replaced with 122.334.567.90
'

funziona benissimo


1

Nel mio makefile uso questo:

@sed -i '/.*Revision:.*/c\'"`svn info -R main.cpp | awk '/^Rev/'`"'' README.md

PS: NON dimenticare che il -i cambia effettivamente il testo nel file ... quindi se il pattern che hai definito come "Revision" cambierà, cambierai anche il pattern per sostituirlo.

Esempio di output:

Abc-Project scritto da John Doe

Revisione: 1190

Quindi, se imposti lo schema "Revisione: 1190" non è ovviamente lo stesso che li definivi come "Revisione:" solo ...


1
cat find_replace | while read pattern replacement ; do
sed -i "/${pattern}/c ${replacement}" file    
done 

Il file find_replace contiene 2 colonne, c1 con motivo da abbinare, c2 con sostituzione, il ciclo sed sostituisce ogni riga che unisce uno dei motivi della variabile 1


No, questo è sbagliato sotto diversi aspetti. Esegui seduna volta con un file di script contenente tutti i rimpiazzi che desideri eseguire. L'esecuzione sed -iripetuta sullo stesso file è un antipasto orribile.
Tripleee,

0

È simile a quello sopra ..

sed 's/[A-Za-z0-9]*TEXT_TO_BE_REPLACED.[A-Za-z0-9]*/This line is removed by the admin./'

3
Ciò cambia FOO=TEXT_TO_BE_REPLACEDin FOO=This line ...tal modo non soddisfa le specifiche.
Jens,

Sì. Il nostro requisito è sostituire l'intera riga con "Questa riga viene rimossa dall'amministratore". se trovassimo la chiave pattren "TEXT_TO_BE_REPLACED". Il comando sopra è soddisfacente. Correggimi se la mia comprensione è sbagliata .. @Jens
Annapureddy Hari

@AnnapureddyHari questa risposta non funziona se il testo prima o dopo la stringa di ricerca contiene qualcosa oltre A-Za-z0-9. Fallisce se c'è un segno di uguale, come sottolineato da Jens. La parte "FOO =" rimarrà; non hai sostituito l'intera riga. Questo codice ha una visione breve di ciò che potrebbe essere nel file. Se intendi jolly, dovresti mettere jolly, come mostra la risposta di Thor.
msouth,

0

Di seguito il comando funziona per me. Che sta lavorando con le variabili

sed -i "/\<$E\>/c $D" "$B"

Ma il mio nuovo requisito è SKIP commentato (inizia con #) riga durante la sostituzione. Poiché stiamo sostituendo la riga completa, verranno sostituite anche le righe commentate e si otterranno proprietà duplicate. Se qualcuno ha una soluzione per questo, per favore fatemelo sapere.
Ritesh Borkar,

-1

Uso molto spesso regex per estrarre dati da file che ho appena usato per sostituire la citazione letterale \"con //nulla :-)

cat file.csv | egrep '^\"([0-9]{1,3}\.[0-9]{1,3}\.)' | sed  s/\"//g  | cut -d, -f1 > list.txt
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.