web-dev-qa-db-fra.com

fichier de modification sed en place

J'essaie de savoir s'il est possible de modifier un fichier dans une seule commande sed sansmanuellementdiffuser en continu le contenu modifié dans un nouveau fichier, puis de renommer le nouveau fichier en nom d'origine. J'ai essayé l'option -i mais mon système Solaris a déclaré que -i était une option illégale. Y a-t-il un moyen différent?

216
amphibient

L'option -i diffuse le contenu modifié dans un nouveau fichier, puis le renomme en coulisse, quoi qu'il en soit.

Exemple:

sed -i 's/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g' filename

et

sed -i '' 's/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g' filename

sur macOS.

320
choroba

Sur un système où sed n'a pas la capacité d'éditer des fichiers sur place, je pense que la meilleure solution serait d'utiliser Perl:

Perl -pi -e 's/foo/bar/g' file.txt

Bien que cela crée un fichier temporaire, il remplace le fichier d'origine car un suffixe/une extension vide a été fourni.

68
Steve

Notez que sous OS X, vous risquez d'obtenir des erreurs étranges telles que "code de commande non valide" ou d'autres erreurs étranges lors de l'exécution de cette commande. Pour résoudre ce problème, essayez 

sed -i '' -e "s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g" <file>

En effet, dans la version OSX de sed, l'option -i attend un argument extension et votre commande est donc analysée comme l'argument extension et le chemin du fichier est interprété comme le code de la commande. Source: https://stackoverflow.com/a/19457213

44
diadyne

Ce qui suit fonctionne bien sur mon mac

sed -i.bak 's/foo/bar/g' sample

Nous remplaçons foo par bar dans le fichier exemple. La sauvegarde du fichier original sera sauvegardée dans sample.bak

Pour éditer inline sans sauvegarde, utilisez la commande suivante

sed -i'' 's/foo/bar/g' sample
21
minhas23

Une chose à noter, sed ne peut pas écrire de fichiers seul, car le seul but de sed est d'agir en tant qu'éditeur sur le "flux" (c'est-à-dire les pipelines de stdin, stdout, stderr et autres tampons >&n, sockets, etc.). Dans cet esprit, vous pouvez utiliser une autre commande tee pour écrire la sortie dans le fichier. Une autre option consiste à créer un correctif à partir du contenu de la tuyauterie dans diff.

Méthode de té

sed '/regex/' <file> | tee <file>

Méthode du patch

sed '/regex/' <file> | diff -p <file> /dev/stdin | patch

METTRE À JOUR:

De plus, notez que patch fera changer le fichier à partir de la ligne 1 de la sortie diff:

Patch n'a pas besoin de savoir à quel fichier accéder car cela se trouve dans la première ligne du résultat de diff:

$ echo foobar | tee fubar

$ sed 's/oo/u/' fubar | diff -p fubar /dev/stdin
*** fubar   2014-03-15 18:06:09.000000000 -0500
--- /dev/stdin  2014-03-15 18:06:41.000000000 -0500
***************
*** 1 ****
! foobar
--- 1 ----
! fubar

$ sed 's/oo/u/' fubar | diff -p fubar /dev/stdin | patch
patching file fubar
11
Dwight Spencer

Il n'est pas possible de faire ce que vous voulez avec sed. Même les versions de sed qui prennent en charge l’option -i pour éditer un fichier sur place font exactement ce que vous avez explicitement déclaré que vous ne voulez pas: elles écrivent dans un fichier temporaire puis le renomment. Mais peut-être pouvez-vous simplement utiliser ed. Par exemple, pour changer toutes les occurrences de foo en bar dans le fichier file.txt, vous pouvez procéder comme suit:

echo ',s/foo/bar/g; w' | tr \; '\012' | ed -s file.txt

La syntaxe est similaire à sed, mais certainement pas exactement la même chose.

Mais peut-être devriez-vous vous demander pourquoi vous ne voulez pas utiliser un fichier temporaire renommé. Même si vous n'avez pas de -i prenant en charge sed, vous pouvez facilement écrire un script pour effectuer le travail à votre place. Au lieu de sed -i 's/foo/bar/g' file, vous pourriez faire inline file sed 's/foo/bar/g'. Un tel script est trivial à écrire. Par exemple:

#!/bin/sh -e
IN=$1
shift
trap 'rm -f $tmp' 0
tmp=$( mktemp )
<$IN "$@" >$tmp && cat $tmp > $IN  # preserve hard links

devrait convenir à la plupart des utilisations.

10
William Pursell

sed prend en charge le montage sur place. De man sed:

-i[SUFFIX], --in-place[=SUFFIX]

    edit files in place (makes backup if extension supplied)

Exemple:

Supposons que vous avez un fichier hello.txtavec le texte:

hello world!

Si vous souhaitez conserver une sauvegarde de l'ancien fichier, utilisez:

sed -i.bak 's/hello/bonjour' hello.txt

Vous allez vous retrouver avec deux fichiers: hello.txt avec le contenu:

bonjour world!

et hello.txt.bak avec l'ancien contenu.

Si vous ne souhaitez pas conserver une copie, ne passez pas le paramètre extension.

7
Sergio A.

Vous pourriez utiliser vi

vi -c '%s/foo/bar/g' my.txt -c 'wq'
7
mench

Si vous remplacez le même nombre de caractères et après avoir lu attentivement Édition «sur place» de fichiers ...

Vous pouvez également utiliser l'opérateur de redirection <> pour ouvrir le fichier à lire et à écrire:

sed 's/foo/bar/g' file 1<> file

Voir en direct:

$ cat file
hello
i am here                           # see "here"
$ sed 's/here/away/' file 1<> file  # Run the `sed` command
$ cat file
hello
i am away                           # this line is changed now

De Manuel de référence Bash → 3.6.10 Ouverture de descripteurs de fichiers pour la lecture et l'écriture :

L'opérateur de redirection

[n]<>Word

provoque l'ouverture du fichier dont le nom est l'extension de Word pour à la fois en lecture et en écriture sur le descripteur de fichier n ou sur le descripteur de fichier 0 si n n'est pas spécifié. Si le fichier n'existe pas, il est créé.

3
fedorqui
mv file.txt file.tmp && sed 's/foo/bar/g' < file.tmp > file.txt

Devrait conserver tous les liens en dur, car la sortie est dirigée vers le dessus pour écraser le contenu du fichier original et évite le besoin d’une version spéciale de sed.

3
JJM

Vous n'avez pas spécifié le shell que vous utilisez, mais avec zsh, vous pouvez utiliser la construction =( ) pour y parvenir. Quelque chose dans le genre de:

cp =(sed ... file; sync) file

=( ) est similaire à >( ) mais crée un fichier temporaire qui est automatiquement supprimé lorsque cp se termine.

1
Thor

Très bons exemples. J'ai eu le défi d'éditer sur place de nombreux fichiers et l'option -i semble être la seule solution raisonnable à l'utiliser dans la commande find. Voici le script pour ajouter "version:" devant la première ligne de chaque fichier:

find . -name pkg.json -print -exec sed -i '.bak' '1 s/^/version /' {} \;
1
Robert

Comme Moneypenny l'a dit dans Skyfall: "Parfois, les vieilles méthodes sont meilleures.".

$ printf ', s/false/true/g\nw\n' | ed {YourFileHere}

Bonne édition en place . Ajouté '\ nw\n' pour écrire le fichier. Toutes mes excuses pour la demande de réponse tardive.

0
jlettvin