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
?
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
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./'
La réponse acceptée n'a pas fonctionné pour moi pour plusieurs raisons:
-i
avec une extension de longueur zéroc\
est bizarre et je ne pouvais pas le faire fonctionnerVoici 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
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.
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/'
pour la manipulation de fichiers de configuration
je suis venu avec cette solution inspirée par Skensell answer
configLine [searchPattern] [replaceLine] [filePath]
ce sera:
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
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 ...
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
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
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./'