J'essaie d'utiliser la commande sed dans un script Shell dans lequel je veux supprimer les lignes qui lisent STARTremoveThisComment
et les lignes qui lisent removeThisCommentEND
.
Je suis capable de le faire quand je le copie dans un nouveau fichier en utilisant
sed 's/STARTremoveThisComment//' > test
Mais comment puis-je faire cela en utilisant le même fichier en entrée et en sortie?
sed -i
_ (ou la version étendue, --in-place
) automatisera le processus normalement effectué avec des implémentations moins avancées, consistant à envoyer la sortie dans un fichier temporaire, puis à le renommer par la suite.
Le -i
est destiné à l'édition sur place et vous pouvez également fournir un suffixe de sauvegarde pour conserver une copie de l'original:
sed -i.bak fileToChange
sed --in-place=.bak fileToChange
Les deux garderont le fichier original dans fileToChange.bak
.
Gardez à l'esprit que l'édition sur place peut ne pas être disponible dans toutes les implémentations sed
mais elle est dans GNU sed
qui devrait être disponible sur toutes les variantes de Linux, selon vos tags.
Si vous utilisez une implémentation plus primitive, vous pouvez utiliser quelque chose comme:
sed 'whatever' oldfile >newfile ; mv newfile oldfile
bien qu'un peu plus de vérification d'erreur serait bien.
Vous pouvez utiliser le drapeau - i pour la modification sur place et le - e pour spécifier une expression de script normale:
sed -i -e 's/pattern_to_search/text_to_replace/' file.txt
Pour supprimer les lignes correspondant à un certain motif, vous pouvez utiliser la syntaxe la plus simple. Notez le drapeau d:
sed -i '/pattern_to_search/d' file.txt
Vous ne devriez vraiment pas utiliser sed pour cela. Cette question semble être ridiculement fréquente, et cela semble très étrange, car la solution générale est tellement triviale, il semble étrange que les gens veuillent savoir comment le faire en sed, en python, en Ruby, etc. Si vous souhaitez qu'un filtre agisse sur une entrée et l'écrase, utilisez le script simple suivant:
#!/bin/sh -e
in=${1?No input file specified}
mv $in ${bak=.$in.bak}
shift
"$@" < $bak > $in
Mettez cela dans votre chemin dans un fichier exécutable nommé inline
, et le problème sera résolu en général. Par exemple:
inline input-file sed -e s/foo/bar/g
Désormais, si vous souhaitez ajouter une logique pour conserver plusieurs sauvegardes, ou si vous disposez d'options pour modifier le schéma de nommage des sauvegardes, ou autre, vous devez le réparer en un seul endroit. Quelle est l'option de ligne de commande pour obtenir des compteurs 1 en 1 sur le fichier de sauvegarde lors du traitement d'un fichier sur place avec Perl
? Qu'en est-il de Ruby
? L'option est-elle différente pour gnu-sed
? Comment awk
le gère-t-il? Le point fondamental de Unix est que les outils ne font qu’une chose. La gestion de la logique des fichiers de sauvegarde est une seconde étape et doit être factorisée. Si vous implémentez un outil, n’ajoutez pas de logique pour créer des fichiers de sauvegarde. Dites à vos utilisateurs d'utiliser un deuxième outil pour cela. L'intégration est mauvaise. La modularité est bonne. C'est la manière unix.
Notez que ce script a plusieurs problèmes. Les autorisations/mode du fichier d'entrée peuvent être modifiés, par exemple. Je suis sûr qu'il y a d'innombrables autres problèmes. Cependant, en plaçant la logique de sauvegarde dans un script wrapper, vous localisez tous ces problèmes et vous n'avez pas à craindre que sed
écrase les fichiers et le mode de modification, tandis que python
conserve le fichier à l'intérieur. place et ne change pas l’inode (j’ai composé ces deux cas, l’idée étant que tous les outils n’utiliseront pas la même logique, alors que le script d’enveloppe le fera.)
Je suggère d'utiliser sponge
sponge lit l’entrée standard et l’écrit dans le fichier spécifié. Contrairement à une redirection de shell, Sponge absorbe toutes ses entrées avant d'écrire le fichier de sortie. Cela permet de construire des pipelines qui lisent et écrivent dans le même fichier.
cat test | sed 's/STARTremoveThisComment//' | sponge test
Autant que je sache, il n'est pas possible d'utiliser le même fichier pour les entrées et les sorties. Bien que l’une des solutions soit de créer un script Shell qui le sauvegarde dans un autre fichier, supprimez l’ancienne entrée et renommez la sortie avec le nom du fichier d’entrée.
sed -e s/try/this/g input.file > output.file;mv output.file input.file