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?
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.
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.
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
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
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
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.
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.txt
avec 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.
Vous pourriez utiliser vi
vi -c '%s/foo/bar/g' my.txt -c 'wq'
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
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éé.
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.
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.
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 /' {} \;
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.