Utilisation du même fichier pour stdin et stdout avec redirection

J’écris une application qui agit comme un filtre: elle lit les entrées d’un fichier (stdin), traite et écrit les résultats dans un autre fichier (stdout). Le fichier d’entrée est complètement lu avant que l’application ne commence à écrire le fichier de sortie.

Comme j’utilise stdin et stdout, je peux courir comme ceci:

$ ./myprog file2.txt 

Cela fonctionne bien, mais si j’essaie d’utiliser le même fichier que l’entrée et la sortie (c’est-à-dire: lire un fichier et écrire dans le même fichier), comme ceci:

 $ ./myprog file.txt 

il nettoie file.txt avant que le programme ait la chance de le lire.

Est-il possible de faire quelque chose comme ça dans une ligne de commande sous Unix?

Le shell est ce qui rend votre fichier de sortie obsolète, car il prépare les descripteurs de fichiers de sortie avant d’ exécuter votre programme. Il n’y a aucun moyen de faire en sorte que votre programme lise l’entrée avant que le shell ne clobe le fichier dans une seule ligne de commande shell.

Vous devez utiliser deux commandes, soit déplacer ou copier le fichier avant de le lire:

 mv file.txt filecopy.txt ./myprog < filecopy.txt > file.txt 

Ou bien encore en sortie vers une copie puis en remplaçant l’original:

 ./myprog < file.txt > filecopy.txt mv filecopy.txt file.txt 

Si vous ne pouvez pas faire cela, vous devez transmettre le nom de fichier à votre programme, ce qui ouvre le fichier en mode lecture / écriture et gère toutes les E / S en interne.

 ./myprog file.txt # reads and writes according to its own rules 

Il y a un utilitaire d’éponge dans le paquet moreutils :

 ./myprog < file.txt | sponge file.txt 

Pour citer le manuel:

Sponge lit les entrées standard et les écrit dans le fichier spécifié. Contrairement à une redirection de shell, l’éponge absorbe toutes ses entrées avant d’ouvrir le fichier de sortie. Cela permet de construire des pipelines qui lisent et écrivent dans le même fichier.

Pour une solution de nature purement académique:

 $ ( unlink file.txt && ./myprog >file.txt )  

Les effets secondaires possibles sont les suivants:

  • Si ./myprog échoue, vous détruisez votre saisie. (Naturellement...)
  • ./myprog s'exécute à partir d'un sous-shell (utilisez { ... ; } au lieu de ( ... ) pour éviter.)
  • file.txt devient un nouveau fichier avec de nouvelles permissions d'inode et de fichier.
  • Vous avez besoin de la permission +w sur le répertoire du file.txt .