Bu eski bir soru olmasına rağmen, bana çok uzun bir soru gibi görünüyor ve şu ana kadar önerilenden daha genel, daha net bir çözüm var. Kredilerin verildiği yerdeki kredi: Stéphane Chazelas'ın <>
güncelleme operatöründen bahsettiğini düşünmeden elde edeceğime emin değilim .
Bir Bourne kabuğundaki güncelleme için dosyayı açmak sınırlı bir yardımcı programdır. Kabuk, bir dosya için arama yapmanıza ve yeni uzunluğunu ayarlamanıza imkan vermez (eskisinden daha kısaysa). Ama bu kolayca çözüldü, bu yüzden kolayca içinde bulunan standart uygulamalar arasında olmadığına şaşırdım /usr/bin
.
Bu çalışıyor:
$ grep -n foo T
8:foo
$ (exec 4<>T; grep foo T >&4 && ftruncate 4) && nl T;
1 foo
Bunun gibi (Stéphane'ye şapka bahşiş verir):
$ { grep foo T && ftruncate; } 1<>T && nl T;
1 foo
(GNU grep kullanıyorum. Belki de cevabını yazdığından beri bir şeyler değişmiştir.)
Ancak, / usr / bin / ftruncate öğeniz yok . Birkaç düzine C çizgisi için aşağıya bakınız. Bu ftruncate yardımcı programı, isteğe bağlı bir dosya tanımlayıcısını, isteğe bağlı bir uzunluğa keser, varsayılan olarak standart çıktıya ve geçerli konuma göre ayarlar.
Yukarıdaki komut (1. örnek)
T
güncelleme için dosya tanımlayıcı 4'ü açar . Open (2) 'de olduğu gibi, dosyayı bu şekilde açmak geçerli ofseti 0'da konumlandırır.
- grep daha sonra
T
normal bir şekilde işler ve kabuk çıktısını T
tanımlayıcı 4 üzerinden yönlendirir .
- ftruncate , tanımlayıcı 4'teki ftruncate (2) işlevini çağırır, uzunluğu geçerli ofset değerine ayarlar (tam olarak grep bıraktığı yer).
Alt kabuk daha sonra tanımlayıcı 4'ü kapatarak çıkar. İşte 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;
}
Not: Bu şekilde kullanıldığında ftruncate (2) taşınabilir değildir. Mutlak genellik için son yazılan baytı okuyun, dosyayı O_WRONLY içinde yeniden açın, arayın, bayt yazın ve kapatın.
Sorunun 5 yaşında olduğu göz önüne alındığında, bu çözümün açık olmadığını söyleyeceğim. Her ikisi de arcane olan yeni bir tanımlayıcı ve operatör açmak için exec'ten faydalanır <>
. Dosya tanıtıcısına göre bir inode'u işleyen standart bir yardımcı program düşünemiyorum. (Sözdizimi olabilir ftruncate >&4
, ancak bir iyileşme olduğundan emin değilim.) Bu, Camh'ın yetkin, keşif yanıtından oldukça kısa. Perl'i benden daha fazla sevmiyorsan, IMP, Stéphane'den biraz daha net. Umarım birileri onu yararlı bulur.
Aynı şeyi yapmanın farklı bir yolu, mevcut ofseti bildiren lseek (2) 'nin çalıştırılabilir bir sürümü olacaktır; çıktı , bazı Linuxi'lerin sağladığı / usr / bin / truncate için kullanılabilir.