Meskipun ini adalah pertanyaan lama, menurut saya ini adalah pertanyaan abadi, dan solusi yang lebih umum, lebih jelas tersedia daripada yang telah dikemukakan sejauh ini. Kredit di mana kredit jatuh tempo: Saya tidak yakin saya akan memunculkannya tanpa mempertimbangkan Stéphane Chazelas tentang <>
operator pembaruan.
Membuka file untuk pembaruan dalam shell Bourne adalah utilitas terbatas. Shell tidak memberi Anda cara untuk mencari pada file, dan tidak ada cara untuk mengatur panjang baru (jika lebih pendek dari yang lama). Tapi itu mudah diatasi, jadi mudah saya terkejut itu bukan salah satu utilitas standar di /usr/bin
.
Ini bekerja:
$ grep -n foo T
8:foo
$ (exec 4<>T; grep foo T >&4 && ftruncate 4) && nl T;
1 foo
Seperti halnya ini (ujung topi ke Stéphane):
$ { grep foo T && ftruncate; } 1<>T && nl T;
1 foo
(Saya menggunakan GNU grep. Mungkin ada yang berubah sejak dia menulis jawabannya.)
Kecuali, Anda tidak memiliki / usr / bin / ftruncate . Untuk beberapa lusin baris C, Anda bisa, lihat di bawah. Utilitas funcuncate ini memotong deskriptor file sewenang-wenang hingga panjang sewenang-wenang, default ke output standar dan posisi saat ini.
Perintah di atas (contoh 1)
- membuka file descriptor 4 pada
T
untuk pembaruan. Sama seperti dengan open (2), membuka file dengan cara ini menempatkan offset saat ini pada 0.
- grep kemudian memproses secara
T
normal, dan shell mengarahkan ulang outputnya ke T
melalui deskriptor 4.
- ftruncate panggilan ftruncate (2) dari deskriptor 4, pengaturan panjang dengan nilai arus offset (persis di mana grep meninggalkannya).
Subshell kemudian keluar, deskriptor penutup 4. Berikut ini 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) tidak dapat diport ketika digunakan dengan cara ini. Untuk generalitas absolut, baca byte tertulis terakhir, buka kembali file O_WRONLY, cari, tulis byte, dan tutup.
Mengingat bahwa pertanyaannya adalah 5 tahun, saya akan mengatakan solusi ini tidak jelas. Dibutuhkan dari eksekutif untuk membuka deskriptor baru, dan <>
operator, yang keduanya misterius. Saya tidak bisa memikirkan utilitas standar yang memanipulasi inode oleh deskriptor file. (Sintaksnya bisa ftruncate >&4
, tapi saya tidak yakin itu perbaikan.) Jauh lebih pendek dari jawaban yang kompeten dan kompeten camh. Itu hanya sedikit lebih jelas daripada Stéphane, IMO, kecuali jika Anda lebih suka Perl daripada saya. Saya harap seseorang menemukannya bermanfaat.
Cara berbeda untuk melakukan hal yang sama adalah versi lseek (2) yang dapat dieksekusi yang melaporkan offset saat ini; outputnya bisa digunakan untuk / usr / bin / truncate , yang disediakan oleh beberapa Linuxi.