web-dev-qa-db-fra.com

Remplace la ligne entière contenant une chaîne en utilisant Sed

J'ai un fichier texte qui a une ligne particulière quelque chose comme

sometext sometext sometext TEXT_TO_BE_REPLACED sometext sometext sometext

Je dois remplacer toute la ligne ci-dessus par

This line is removed by the admin.

Le mot clé de recherche est TEXT_TO_BE_REPLACED

J'ai besoin d'écrire un script Shell pour cela. Comment puis-je réaliser cela en utilisant sed?

267
Rahul

Vous pouvez utiliser la commande change pour remplacer la ligne entière et le drapeau -i pour apporter les modifications à la place. Par exemple, en utilisant GNU sed:

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

Vous devez utiliser des wildards (.*) avant et après pour remplacer la ligne entière:

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

La réponse acceptée n'a pas fonctionné pour moi pour plusieurs raisons:

  • ma version de sed n'aime pas -i avec une extension de longueur zéro
  • la syntaxe de la commande c\ est bizarre et je ne pouvais pas le faire fonctionner
  • Je ne savais pas que certains de mes problèmes venaient de barres obliques non échappées

Voici donc la solution que je propose qui devrait fonctionner dans la plupart des cas:

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/
}

Donc, l'exemple d'utilisation pour résoudre le problème posé:

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

La réponse ci-dessus:

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

Fonctionne bien si la chaîne/ligne de remplacement n'est pas une variable.

Le problème est que sur Redhat 5, le \ après le c échappe au $. Un double \\ ne fonctionnait pas non plus (du moins sur Redhat 5).

Grâce à hit et à trial, j'ai découvert que le \ après le c est redondant si votre chaîne/ligne de remplacement ne contient qu'une seule ligne. Donc, je n'ai pas utilisé \ après le c, j'ai utilisé une variable comme ligne de remplacement unique et c'était une joie.

Le code ressemblerait à quelque chose comme:

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

Notez l'utilisation de guillemets doubles au lieu de guillemets simples.

11
user4256255

Toutes les réponses fournies jusqu'à présent supposent que vous sachiez quelque chose sur le texte à remplacer, ce qui a du sens, puisque c'est ce que le PO a demandé. Je fournis une réponse qui suppose que vous ne savez rien du texte à remplacer et qu'il peut y avoir une ligne séparée dans le fichier avec le même contenu ou un contenu similaire que vous ne souhaitez pas remplacer. De plus, je suppose que vous connaissez le numéro de la ligne à remplacer.

Les exemples suivants illustrent la suppression ou la modification de texte par des numéros de ligne spécifiques:

# 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
b_laoshi

pour la manipulation de fichiers de configuration

je suis venu avec cette solution inspirée par Skensell answer

configLine [searchPattern] [replaceLine] [filePath]

ce sera:

  • créer le fichier s'il n'existe pas
  • remplace la ligne entière (toutes les lignes) où searchPattern correspond
  • ajouter replaceLine à la fin du fichier si aucun motif n'a été trouvé

Une fonction:

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 magie de l'état de sortie fou vient de https://stackoverflow.com/a/12145797/126266

2
Grain

J'utilise ceci dans mon makefile:

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

PS: NE PAS PAS oublier que le -i change réellement le texte du fichier ... donc si le motif que vous avez défini comme "Révision" va changer, vous allez aussi changer le motif à remplacer.

Exemple de sortie:

Abc-Project écrit par John Doe

Révision: 1190

Donc, si vous définissez le motif "Révision: 1190", ce n'est évidemment pas la même chose que vous les avez définies comme "Révision:" seulement ...

1
Martin Pfeffer
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
'

ça fonctionne bien

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

le fichier find_replace contient 2 colonnes, c1 avec motif à rechercher, c2 avec remplacement, la boucle sed remplace chaque ligne contenant l'un des motifs de la variable 1

1
sjordi

C'est comme semblable à ci-dessus un ..

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