112 votes

Comment puis-je utiliser un fichier dans une commande et rediriger la sortie vers le même fichier sans le tronquer ?

Fondamentalement, je veux prendre en entrée du texte depuis un fichier, supprimer une ligne de ce fichier, et renvoyer la sortie vers le même fichier. Quelque chose dans ce sens si cela rend les choses plus claires.

grep -v 'seg[0-9]\{1,\}\.[0-9]\{1\}' file_name > file_name

Cependant, lorsque je fais cela, je me retrouve avec un fichier vide. Des idées?

109voto

Lynch Points 2534

Utilisez sponge pour ce type de tâches. Il fait partie de moreutils.

Essayez cette commande:

 grep -v 'seg[0-9]\{1,\}\.[0-9]\{1\}' nom_fichier | sponge nom_fichier

4 votes

Merci pour la réponse. Comme une addition potentiellement utile, si vous utilisez homebrew sur Mac, vous pouvez utiliser brew install moreutils.

3 votes

Ou sudo apt-get install moreutils sur les systèmes basés sur Debian.

3 votes

Diantre! Merci de m'avoir fait découvrir moreutils =) de beaux programmes là-bas!

95voto

c00kiemon5ter Points 5561

Vous ne pouvez pas faire cela car bash traite d'abord les redirections, puis exécute la commande. Donc, lorsque grep regarde file_name, il est déjà vide. Vous pouvez cependant utiliser un fichier temporaire.

#!/bin/sh
tmpfile=$(mktemp)
grep -v 'seg[0-9]\{1,\}\.[0-9]\{1\}' file_name > ${tmpfile}
cat ${tmpfile} > file_name
rm -f ${tmpfile}

de cette manière, envisagez d'utiliser mktemp pour créer le tmpfile mais notez que ce n'est pas POSIX.

50 votes

La raison pour laquelle vous ne pouvez pas faire cela : bash traite d'abord les redirections, puis exécute la commande. Donc, lorsque grep regarde le nom du fichier, celui-ci est déjà vide.

1 votes

@glennjackman : par "redirection des processus", voulez-vous dire que dans le cas de >, il ouvre le fichier et le vide, et dans le cas de >>, il l'ouvre simplement?

2 votes

Oui, mais à noter dans cette situation, la redirection > ouvrira le fichier et le tronquera avant le lancement de la coquille grep.

20voto

Manny D Points 4682

Utilisez sed à la place :

sed -i '/seg[0-9]\{1,\}\.[0-9]\{1\}/d' nom_fichier

1 votes

Je crois que -i est une extension spécifique à GNU, juste pour noter.

4 votes

Sur *BSD (et donc aussi sur OSX), vous pouvez dire -i '' ainsi l'extension n'est pas strictement obligatoire, mais l'option -i nécessite quelque argument.

15voto

sailesh ramanam Points 119

Essayez celui-ci simple

grep -v 'seg[0-9]\{1,\}\.[0-9]\{1\}' nom_fichier | tee nom_fichier

Votre fichier ne sera pas vide cette fois :) et votre sortie est également imprimée dans votre terminal.

1 votes

J'aime cette solution! Et si vous ne voulez pas qu'elle soit imprimée dans le terminal, vous pouvez toujours rediriger la sortie vers /dev/null ou des endroits similaires.

6 votes

Cela efface également le contenu du fichier ici. Est-ce dû à une différence entre GNU/BSD ? Je suis sur macOS...

1 votes

Pas garanti, même que stackoverflow.com/a/51173807/97439

7voto

w00t Points 134

Alternative d'une seule ligne - définir le contenu du fichier comme variable:

VAR=`cat file_name`; echo "$VAR"|grep -v 'seg[0-9]\{1,\}\.[0-9]\{1\}' > file_name

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X