web-dev-qa-db-fra.com

Rechercher et remplacer dans le fichier et écraser le fichier ne fonctionne pas, il vide le fichier

Je voudrais exécuter une recherche et remplacer sur un fichier HTML via la ligne de commande.

Ma commande ressemble à quelque chose comme ça:

sed -e s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g index.html > index.html

Lorsque je lance ceci et que je regarde le fichier par la suite, il est vide. Il a supprimé le contenu de mon dossier.

Quand je lance ceci après avoir restauré le fichier:

sed -e s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g index.html

Le stdout est le contenu du fichier, et la recherche et le remplacement ont été exécutés.

Pourquoi cela arrive-t-il?

574
BBales

Lorsque Shell voit > index.html dans la ligne de commande, il ouvre le fichier index.html pour écriture, en effaçant tout son contenu précédent.

Pour résoudre ce problème, vous devez passer l'option -i à sed pour effectuer les modifications en ligne et créer une sauvegarde du fichier d'origine avant les modifications sur place:

sed -i.bak s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g index.html

Sans le .bak, la commande échouera sur certaines plates-formes, telles que Mac OSX.

886
codaddict

Un modèle alternatif, utile, est:

sed -e 'script script' index.html > index.html.tmp && mv index.html.tmp index.html

Cela a pratiquement le même effet, sans utiliser l'option -i, et signifie en outre que, si le script sed échoue pour une raison quelconque, le fichier d'entrée n'est pas compressé. De plus, si l'édition réussit, il ne reste aucun fichier de sauvegarde. Ce genre d'idiome peut être utile dans Makefiles.

Beaucoup de seds ont l'option -i, mais pas tous; le posix sed est celui qui ne le fait pas. Si vous visez la portabilité, évitez-la.

201
Norman Gray
sed -i 's/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g' index.html

Cela effectue une substitution globale sur place dans le fichier index.html. La citation de la chaîne évite les problèmes de blancs dans la requête et de remplacement.

88
Rich Apodaca

utilisez l'option -i de sed, par exemple.

sed -i bak -e s/STRING_TO_REPLACE/REPLACE_WITH/g index.html
56
Kevin

Pour modifier plusieurs fichiers (et enregistrer une sauvegarde de chacun sous le nom * .bak):

Perl -p -i -e "s/\|/x/g" *  

va prendre tous les fichiers dans le répertoire et remplacer | par x c'est ce qu'on appelle un "camembert Perl" (simple comme bonjour)

18
Stenemo

Vous devriez essayer d'utiliser l'option -i pour l'édition sur place.

14
uloBasEI

Attention: il s'agit d'une méthode dangereuse! Il abuse des tampons d'E/S sous Linux et, avec des options spécifiques de mise en tampon, il parvient à fonctionner sur de petits fichiers. C'est une curiosité intéressante. Mais ne l'utilisez pas pour une situation réelle!

Outre l'option -i de sed, vous pouvez utiliser l'utilitaire tee.

De man:

tee - lit à partir de l'entrée standard et écrit dans la sortie standard et les fichiers

Donc, la solution serait:

sed s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g index.html | tee | tee index.html

- ici, tee est répété pour s'assurer que le pipeline est mis en mémoire tampon. Ensuite, toutes les commandes du pipeline sont bloquées jusqu'à ce qu'elles aient une entrée sur laquelle travailler. Chaque commande du pipeline commence lorsque les commandes en amont ont écrit 1 tampon d'octets (la taille est définie quelque part ) dans l'entrée de la commande. Ainsi, la dernière commande tee index.html, qui ouvre le fichier en écriture et le vide par conséquent, est exécutée une fois le pipeline en amont terminé et que la sortie se trouve dans la mémoire tampon du pipeline.

Très probablement, les éléments suivants ne fonctionneront pas:

sed s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g index.html | tee index.html

- il lancera les deux commandes du pipeline en même temps sans aucun blocage. (Sans bloquer le pipeline, les octets doivent passer ligne par ligne et non tampon par tampon. Idem que lorsque vous exécutez cat | sed s/bar/GGG/. Sans le bloquer, il est plus interactif et généralement des pipelines de seulement 2 commandes sont exécutés sans tampon ni blocage. Les pipelines plus longs sont mis en mémoire tampon.) Le tee index.html ouvrira le fichier en écriture et le videra. Cependant, si vous activez toujours la mise en mémoire tampon, la deuxième version fonctionnera également.

6
xealits
sed -i.bak "s#https.*\.com#$pub_url#g" MyHTMLFile.html

Si vous avez un lien à ajouter, essayez ceci. Recherchez l'URL comme ci-dessus (en commençant par https et finissez par.com ici) et remplacez-la par une chaîne d'URL. J'ai utilisé une variable $pub_url ici. s signifie ici recherche et g signifie remplacement global.

Ça marche !

6
Kaey

Le problème avec la commande

sed 'code' file > file

est-ce que file est tronqué par le shell avant que sed puisse réellement le traiter. En conséquence, vous obtenez un fichier vide.

Pour ce faire, la méthode la plus simple consiste à utiliser -i pour le modifier à la place, comme suggéré par d'autres réponses. Cependant, ce n'est pas toujours ce que vous voulez. -i créera un fichier temporaire qui sera ensuite utilisé pour remplacer le fichier d'origine. Ceci est problématique si votre fichier d'origine était un lien (le lien sera remplacé par un fichier normal). Si vous devez conserver des liens, vous pouvez utiliser une variable temporaire pour stocker la sortie de sed avant de l'écrire dans le fichier, comme suit:

tmp=$(sed 'code' file); echo -n "$tmp" > file

Mieux encore, utilisez printf au lieu de echo puisque echo est susceptible de traiter \\ comme \ dans certains shells (par exemple, tiret):

tmp=$(sed 'code' file); printf "%s" "$tmp" > file
4
Andrzej Pronobis

Et la ed répond:

printf "%s\n" '1,$s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g' w q | ed index.html

Pour rappeler ce que réponse codaddict , le shell gère la redirection en premier , en effaçant le fichier "input.html", et puis le shell appelle la commande "sed" en lui transmettant un fichier maintenant vide.

3
glenn jackman

Vous pouvez utiliser Vim en mode Ex:

ex -sc '%s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g|x' index.html
  1. % sélectionner toutes les lignes

  2. x enregistrer et fermer

2
Steven Penny

Je cherchais l'option permettant de définir la plage de lignes et de trouver la réponse. Par exemple, je souhaite remplacer Host1 par Host2 à partir des lignes 36-57.

sed '36,57 s/Host1/Host2/g' myfile.txt > myfile1.txt

Vous pouvez également utiliser l’option gi pour ignorer la casse des caractères.

sed '30,40 s/version/story/gi' myfile.txt > myfile1.txt
0
user8117884

En tout respect pour les réponses correctes ci-dessus, il est toujours bon de "sécher" des scripts comme celui-ci, afin de ne pas corrompre votre fichier et de devoir tout recommencer à zéro.

Demandez à votre script de renvoyer la sortie sur la ligne de commande au lieu de l'écrire dans le fichier, par exemple, comme ceci:

sed -e s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g index.html

OR

less index.html | sed -e s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g 

De cette façon, vous pouvez voir et vérifier le résultat de la commande sans que votre fichier soit tronqué.

0
Nestor Milyaev