Aunque esta es una vieja pregunta, me parece que es una pregunta perenne, y hay disponible una solución más general y más clara de lo que se ha sugerido hasta ahora. Crédito donde se debe el crédito: no estoy seguro de haberlo ideado sin tener en cuenta la mención de Stéphane Chazelas del <>
operador de actualización.
Abrir un archivo para actualizarlo en un shell Bourne es de utilidad limitada. El shell no le da forma de buscar en un archivo, y no tiene forma de establecer su nueva longitud (si es más corta que la anterior). Pero eso se soluciona fácilmente, así que me sorprende que no esté entre las utilidades estándar /usr/bin
.
Esto funciona:
$ grep -n foo T
8:foo
$ (exec 4<>T; grep foo T >&4 && ftruncate 4) && nl T;
1 foo
Como hace esto (punta de sombrero para Stéphane):
$ { grep foo T && ftruncate; } 1<>T && nl T;
1 foo
(Estoy usando GNU grep. Quizás algo ha cambiado desde que escribió su respuesta).
Excepto que no tienes / usr / bin / ftruncate . Para un par de docenas de líneas de C, puede ver a continuación. Esta utilidad ftruncate trunca un descriptor de archivo arbitrario a una longitud arbitraria, por defecto a la salida estándar y la posición actual.
El comando anterior (primer ejemplo)
- abre el descriptor de archivo 4
T
para actualización. Al igual que con open (2), al abrir el archivo de esta manera, el desplazamiento actual se sitúa en 0.
- grep luego procesa
T
normalmente, y el shell redirige su salida a T
través del descriptor 4.
- ftruncate llama a ftruncate (2) en el descriptor 4, configurando la longitud al valor del desplazamiento actual (exactamente donde grep lo dejó).
El subshell luego sale, cerrando el descriptor 4. Aquí está 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) no es portátil cuando se usa de esta manera. Para una generalidad absoluta, lea el último byte escrito, vuelva a abrir el archivo O_WRONLY, busque, escriba el byte y cierre.
Dado que la pregunta tiene 5 años, voy a decir que esta solución no es obvia. Se aprovecha el exec para abrir un nuevo descriptor y el <>
operador, los cuales son arcanos. No puedo pensar en una utilidad estándar que manipule un inodo por descriptor de archivo. (La sintaxis podría ser ftruncate >&4
, pero no estoy seguro de que sea una mejora). Es considerablemente más corta que la respuesta exploratoria competente de Camh. Es solo un poco más claro que Stéphane's, en mi opinión, a menos que te guste Perl más que a mí. Espero que alguien lo encuentre útil.
Una forma diferente de hacer lo mismo sería una versión ejecutable de lseek (2) que informa el desplazamiento actual; la salida podría usarse para / usr / bin / truncate , que algunos Linuxi proporcionan.