Même s’il s’agit d’une question ancienne, il me semble que c’est une question éternelle et qu’une solution plus générale et plus claire que celle suggérée jusqu’à présent est disponible. Le crédit est dû: Je ne suis pas sûr que je l'aurais trouvé sans tenir compte de la mention de Stéphane Chazelas sur l' <>
opérateur de mise à jour.
L’ouverture d’un fichier à mettre à jour dans un shell Bourne est d’une utilité limitée. Le shell ne vous donne aucun moyen de rechercher sur un fichier, ni de définir sa nouvelle longueur (si elle est plus courte que l’ancien). Mais on y résout facilement, si facilement que je suis surpris que ce ne soit pas un utilitaire standard de Windows /usr/bin
.
Cela marche:
$ grep -n foo T
8:foo
$ (exec 4<>T; grep foo T >&4 && ftruncate 4) && nl T;
1 foo
De même que cela (astuce à Stéphane):
$ { grep foo T && ftruncate; } 1<>T && nl T;
1 foo
(J'utilise GNU grep. Peut-être que quelque chose a changé depuis qu'il a écrit sa réponse.)
Sauf que vous n'avez pas / usr / bin / ftruncate . Pour une douzaine de lignes de C, vous pouvez, voir ci-dessous. Cet utilitaire ftruncate tronque un descripteur de fichier arbitraire à une longueur arbitraire, par défaut à la sortie standard et à la position actuelle.
La commande ci-dessus (1er exemple)
- ouvre le descripteur de fichier 4 sur
T
pour la mise à jour. Comme avec open (2), ouvrir le fichier de cette façon positionne le décalage actuel à 0.
- grep traite ensuite
T
normalement et le shell redirige sa sortie T
via le descripteur 4.
- ftruncate appelle ftruncate (2) sur le descripteur 4, en fixant la longueur à la valeur de l'offset actuel (exactement là où grep l'a laissé).
Le sous-shell se ferme alors, fermant le descripteur 4. Voici ftruncate :
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int
main( int argc, char *argv[] ) {
off_t i, fd=1, len=0;
off_t *addrs[2] = { &fd, &len };
for( i=0; i < argc-1; i++ ) {
if( sscanf(argv[i+1], "%lu", addrs[i]) < 1 ) {
err(EXIT_FAILURE, "could not parse %s as number", argv[i+1]);
}
}
if( argc < 3 && (len = lseek(fd, 0, SEEK_CUR)) == -1 ) {
err(EXIT_FAILURE, "could not ftell fd %d as number", (int)fd);
}
if( 0 != ftruncate((int)fd, len) ) {
err(EXIT_FAILURE, argc > 1? argv[1] : "stdout");
}
return EXIT_SUCCESS;
}
NB, ftruncate (2) est non-portable lorsqu'il est utilisé de cette façon. Pour une généralité absolue, lisez le dernier octet écrit, rouvrez le fichier O_WRONLY, recherchez, écrivez l'octet et fermez-le.
Étant donné que la question a 5 ans, je vais dire que cette solution est non évidente. Il profite d’ exec pour ouvrir un nouveau descripteur et l’ <>
opérateur, qui sont tous les deux arcanes. Je ne peux pas penser à un utilitaire standard qui manipule un inode par descripteur de fichier. (La syntaxe pourrait être ftruncate >&4
, mais je ne suis pas sûr que ce soit une amélioration.) Elle est considérablement plus courte que la réponse compétente et exploratoire de camh. C'est un peu plus clair que celui de Stéphane, OMI, à moins que vous n'aimiez plus Perl que moi. J'espère que quelqu'un le trouvera utile.
Une autre façon de faire la même chose serait une version exécutable de lseek (2) qui rapporte le décalage actuel; la sortie pourrait être utilisée pour / usr / bin / truncate , fourni par certains Linuxi.