Karena bug aplikasi belum terdiagnosis, saya memiliki beberapa ratus server dengan disk penuh. Ada satu file yang telah diisi dengan duplikat baris - bukan file log, tetapi file lingkungan pengguna dengan definisi variabel (jadi saya tidak bisa hanya menghapus file).
Saya menulis sed
perintah sederhana untuk memeriksa baris yang ditambahkan secara salah dan menghapusnya, dan mengujinya pada salinan lokal file tersebut. Ini berfungsi sebagaimana dimaksud.
Namun, ketika saya mencobanya di server dengan disk penuh, saya mendapatkan kira-kira kesalahan berikut (ini dari memori, bukan salin dan tempel):
sed: couldn't flush /path/to/file/sed8923ABC: No space left on deviceServerHostname
Tentu saja, saya tahu tidak ada ruang yang tersisa. Itu sebabnya saya mencoba menghapus barang! ( sed
Perintah yang saya gunakan akan mengurangi 4000 baris file menjadi sekitar 90 baris.)
sed
Perintah saya adilsed -i '/myregex/d' /path/to/file/filename
Apakah ada cara saya dapat menerapkan perintah ini meskipun disk penuh?
(Ini harus otomatis, karena saya perlu menerapkannya ke beberapa ratus server sebagai perbaikan cepat.)
(Jelas bug aplikasi perlu didiagnosis, tetapi sementara itu server tidak berfungsi dengan benar ....)
Pembaruan: Situasi yang saya hadapi diselesaikan dengan menghapus sesuatu yang saya temukan dapat saya hapus, tetapi saya masih menginginkan jawaban untuk pertanyaan ini , yang akan membantu di masa depan dan untuk orang lain.
/tmp
adalah no-go; ada di sistem file yang sama.
Sebelum saya membebaskan ruang disk, saya melakukan pengujian dan menemukan bahwa saya dapat menghapus baris vi
dengan membuka file dan menjalankan :g/myregex/d
dan kemudian berhasil menyimpan perubahan dengan :wq
. Tampaknya mungkin untuk mengotomatisasi ini, tanpa menggunakan sistem file terpisah untuk menyimpan file temp .... (?)
sumber
sed -i
membuat salinan sementara untuk beroperasi. Saya menduga itued
akan lebih baik untuk ini, meskipun saya tidak cukup akrab untuk melarang solusi yang sebenarnyaed
Anda menjalankan:printf %s\\n g/myregex/d w q | ed -s infile
tetapi perlu diingat beberapa implementasi juga menggunakan file sementara sepertised
(Anda dapat mencoba busybox ed - afaik itu tidak membuat file sementara)echo
. gunakanprintf
. dansed
tambahkan beberapa char yang kamu jatuhkan di baris terakhir agar kamu tidak kehilangan trailing blank. juga, shell Anda harus dapat menangani seluruh file dalam satu baris perintah. itu risiko Anda - tes dulu.bash
sangat buruk pada saat itu (saya pikir itu untuk melakukan ruang w / stack?) dan mungkin sakit pada Anda setiap saat. kedua yangsed
direkomendasikan setidaknya akan menggunakan buffer pipa kernel untuk efek yang baik di antara mereka, tetapi metode ini cukup mirip. Sub perintah Anda juga akan memotongfile
apakah sed tidak berhasil.sed '/regex/!H;$!d;x' <file|{ read v && cat >file;}
dan jika berhasil baca sisa jawaban saya. 'Jawaban:
The
-i
pilihan tidak benar-benar menimpa file asli. Itu membuat file baru dengan output, kemudian mengganti nama ke nama file asli. Karena Anda tidak memiliki ruang pada sistem file untuk file baru ini, gagal.Anda harus melakukannya sendiri di skrip Anda, tetapi buat file baru di sistem file yang berbeda.
Juga, jika Anda hanya menghapus baris yang cocok regexp, Anda dapat menggunakan
grep
bukansed
.Secara umum, sangat jarang bagi program untuk menggunakan file yang sama dengan input dan output - segera setelah mulai menulis ke file, bagian dari program yang membaca dari file tidak akan lagi melihat konten asli. Jadi harus menyalin file asli di suatu tempat terlebih dahulu, atau menulis ke file baru dan mengganti nama ketika selesai.
Jika Anda tidak ingin menggunakan file sementara, Anda bisa mencoba menyimpan konten file dalam memori:
sumber
rsync -a --no-owner --no-group --remove-source-files "$backupfile" "$destination"
dari sinised -i
hal itu tidak terjadi?sed -i
tidak melindungi hal-hal itu. Saya baru saja mencobanya dengan file yang tidak saya miliki, tetapi terletak di direktori yang saya miliki sendiri, dan itu membiarkan saya mengganti file. Pengganti dimiliki oleh saya, bukan pemilik aslinya.var=$(< FILE); echo "$FILE" | grep '^"' > FILE
v=$(<file)&& printf %s\\n "$v" >file
tetapi Anda bahkan tidak menggunakan&&
. Penanya berbicara tentang menjalankannya dalam skrip - mengotomatisasi menimpa file dengan sebagian dari dirinya sendiri. Anda setidaknya harus memvalidasi Anda berhasil membuka input dan output. Shell juga bisa meledak.Begitulah cara
sed
kerjanya. Jika digunakan dengan-i
(di tempat sunting)sed
membuat file sementara dengan konten baru dari file yang diproses. Setelah selesaised
, ganti file yang aktif saat ini dengan yang sementara. Utilitas tidak mengedit file di tempat . Itulah perilaku setiap editor.Ini seperti Anda melakukan tugas berikut dalam sebuah shell:
Pada titik ini
sed
, cobalah untuk menyiram data yang disangga ke file yang disebutkan dalam pesan kesalahan denganfflush()
panggilan sistem:Untuk masalah Anda, saya melihat solusi dalam memasang sistem file separte (misalnya a
tmpfs
, jika Anda memiliki cukup memori, atau perangkat penyimpanan eksternal) dan memindahkan beberapa file di sana, memprosesnya di sana, dan memindahkannya kembali.sumber
Sejak memposting pertanyaan ini saya telah belajar bahwa
ex
ini adalah program yang sesuai dengan POSIX. Ini hampir secara universal terhubung kevim
, tetapi bagaimanapun juga, berikut ini (saya pikir) adalah titik kunciex
dalam kaitannya dengan sistem file (diambil dari spesifikasi POSIX):"... akan memengaruhi file apa pun ..." Saya percaya bahwa meletakkan sesuatu pada sistem file (sama sekali, bahkan file temp) akan dianggap sebagai "memengaruhi file apa pun." Mungkin?*
Studi cermat terhadap spesifikasi POSIX untuk
ex
mengindikasikan beberapa "gotchas" tentang penggunaan portabel yang dimaksud bila dibandingkan dengan penggunaan scripted umum yangex
ditemukan secara online (yang dikotori denganvim
perintah-spesifik.)+cmd
adalah opsional sesuai dengan POSIX.-c
opsi juga opsional.:g
"memakan" semuanya hingga baris baru yang tidak diloloskan (dan karenanya menjalankannya setelah setiap kecocokan ditemukan untuk regex daripada sekali pada akhir). Jadi-c 'g/regex/d | x'
hanya hapus satu instance dan kemudian keluar file.Jadi menurut apa yang saya teliti, metode yang sesuai dengan POSIX untuk mengedit file pada sistem file lengkap untuk menghapus semua baris yang cocok dengan regex tertentu, adalah:
Ini akan berfungsi asalkan Anda memiliki memori yang cukup untuk memuat file ke buffer.
* Jika Anda menemukan sesuatu yang menunjukkan sebaliknya, tolong sebutkan di komentar.
sumber
ex +g/match/d -scx file
apakah POSIX-compliant juga?vi
bekerja pada sistem file lengkap, saya percaya bahwa dalam kebanyakan kasus itu akan bekerja denganex
baik - meskipun mungkin tidak untuk file yang ginormous.sed -i
tidak bekerja pada sistem file lengkap tanpa memperhatikan ukuran file.Gunakan pipanya, Luke!
Baca file | filter | menulis kembali
dalam hal
sed
ini tidak membuat file baru dan hanya mengirim output yang disalurkan kedd
mana membuka file yang sama . Tentu saja orang dapat menggunakannyagrep
dalam kasus tertentukemudian potong sisanya.
sumber
sed
selalu menggunakan file temp?grep
toh tidak akansponge
perintah. Ya,sed
dengan-i
selalu membuat file lilke "seduyUdmw" dengan 000 hak.Seperti dicatat dalam jawaban lain,
sed -i
berfungsi dengan menyalin file ke file baru di direktori yang sama , membuat perubahan dalam proses, dan kemudian memindahkan file baru di atas yang asli. Itu sebabnya itu tidak berhasil.ed
(editor baris asli) bekerja dengan cara yang agak mirip, tetapi, terakhir kali saya memeriksa, ini digunakan/tmp
untuk file awal. Jika Anda/tmp
menggunakan sistem file yang berbeda dari yang penuh,ed
dapat melakukan pekerjaan untuk Anda.Coba ini (di prompt shell interaktif Anda):
The
P
(yang merupakan ibukota P) tidak benar-benar diperlukan. Menyala saat diminta; tanpanya, Anda bekerja dalam kegelapan, dan beberapa orang merasa ini membingungkan. Thew
danq
yang w ritus dan q uit.Jika
/tmp
direktori Anda berada di sistem file yang penuh (atau jika sistem file penuh, juga), cobalah untuk menemukan ruang di suatu tempat. chaos disebutkan memasang tmpfs atau perangkat penyimpanan eksternal (misalnya, flash drive); tetapi, jika Anda memiliki beberapa filesystem, dan mereka tidak semua penuh, Anda dapat hanya menggunakan salah satu dari yang sudah ada lainnya. chaos menyarankan untuk menyalin file ke sistem file lain, mengeditnya di sana (dengansed
), dan kemudian menyalinnya kembali. Pada titik ini, itu mungkin solusi paling sederhana. Tetapi alternatifnya adalah membuat direktori yang dapat ditulis pada sistem file yang memiliki beberapa ruang kosong, mengatur variabel lingkunganTMPDIR
untuk menunjuk ke direktori itu, dan kemudian jalankaned
. (Pengungkapan: Saya tidak yakin apakah ini akan berhasil, tetapi tidak ada salahnya.)Setelah Anda mulai
ed
bekerja, Anda dapat mengotomatisasi ini dengan melakukannyadalam naskah. Atau , seperti yang disarankan oleh don_crissti.
printf '%s\n' 'g/myregex/d' w q | ed -s filename
sumber
ed
atau denganex
) sedemikian rupa sehingga memori digunakan daripada sistem file yang terpisah? Itulah tujuan saya sebenarnya (dan alasan saya belum menerima jawaban.)ed
banyak tahun yang lalu. Masih ada hal-hal seperti komputer 16-bit, di mana proses dibatasi pada ruang alamat 64K (!), Sehingga gagasan editor membaca seluruh file ke dalam memori adalah non-starter. Sejak itu, tentu saja, memori menjadi lebih besar - tetapi begitu juga disk dan file. Karena disk sangat besar, orang tidak merasa perlu berurusan dengan kemungkinan/tmp
kehabisan ruang. Saya hanya melihat sekilas kode sumber versi terbarued
, dan sepertinya ... (Lanjutan)ed
(atauex
atauvi
) versi apa pun menawarkan opsi untuk menjaga buffer dalam memori. Di sisi lain, Penyuntingan Teks dengan ed dan vi - Bab 11: Pemrosesan Teks - Bagian II: Menjelajahi Red Hat Linux - Red Hat Linux 9 Rahasia Profesional - Sistem Linux mengatakan bahwaed
penyunting edit berada di memori, ... (Lanjutan) )vi
(yang merupakan program yang sama denganex
). Saya percaya bahwa mereka hanya menggunakan kata-kata yang ceroboh dan tidak tepat - tetapi, jika itu ada di Internet (atau dalam bentuk cetak), itu pasti benar, bukan? Anda membayar uang Anda dan mengambil pilihan Anda.Anda dapat memotong file dengan cukup mudah jika Anda bisa mendapatkan jumlah byte ke offset Anda dan garis Anda muncul dari titik awal hingga akhir.
Atau jika Anda
${TMPDIR:-/tmp}
menggunakan beberapa sistem file lain, mungkin:Karena (kebanyakan) shell meletakkan dokumen-dokumennya di sini dalam file temp yang dihapus. Ini sangat aman selama
<<FILE
deskriptor dipertahankan dari awal hingga akhir dan${TMPDIR:-/tmp}
memiliki ruang sebanyak yang Anda butuhkan.Kerang yang tidak menggunakan file temp menggunakan pipa, jadi tidak aman untuk menggunakan cara ini. Kerang ini biasanya
ash
derivatif sepertibusybox
,dash
, BSDsh
-zsh
,bash
,ksh
, dan Bourne shell, bagaimanapun, semua file menggunakan temp.rupanya saya menulis program shell kecil Juli lalu untuk melakukan sesuatu yang sangat seperti ini
Jika
/tmp
tidak layak, maka selama Anda dapat memuat file dalam memori seperti ...... sebagai kasus umum paling tidak akan memastikan bahwa file telah sepenuhnya disangga oleh
sed
proses pertama sebelum mencoba untuk memotong file in / out.Solusi yang lebih tepat sasaran dan efisien adalah:
... karena toh tidak akan mengganggu garis penyangga yang ingin Anda hapus.
Tes kasus umum:
sumber
/tmp
yang berada pada sistem file yang sama. Saya sukased
versi ganda Anda . Saya pikir kombinasi jawaban Barmar dan jawaban Anda mungkin yang terbaik, kira-kira seperti:myvar="$(sed '/myregex/d' < file)" && [ -n "$myvar" ] && echo "$myvar" > file ; unset myvar
(Untuk kasus ini saya tidak peduli tentang menjaga jalur baru.)sed
|cat
hal di atas tidak pernah membuka output kecualised
telah buffered seluruh file dan siap untuk mulai menulis semuanya untuk output. Jika mencoba untuk buffer file dan gagal -read
tidak berhasil karena menemukan EOF di|
pipa sebelum membaca baris pertama pertama dan karenanyacat >out
tidak pernah terjadi sampai waktunya untuk menuliskannya dari memori sepenuhnya. meluap atau sesuatu seperti itu baru saja gagal. juga seluruh pipa mengembalikan keberhasilan atau kegagalan setiap saat. menyimpannya di var lebih berisiko.file=$(sed '/regex/!H;$!d;x' <file | read v && tee file) && cmp - file <<<"$file" || shite
jadi file output dan var akan ditulis secara bersamaan, yang akan membuat salah satu atau cadangan yang efektif , yang merupakan satu-satunya alasan Anda ingin mempersulit hal-hal lebih jauh dari yang Anda butuhkan.read script
danread v
jawaban Anda. Jika Anda dapat menguraikan lebih lanjut tentang itu saya akan sangat dihargai, terima kasih!$script
adalahsed
skrip yang akan Anda gunakan untuk menargetkan bagian file apa pun yang Anda inginkan; ini skrip yang memberi Anda hasil akhir yang Anda inginkan dalam aliran.v
hanyalah pengganti untuk baris kosong. dalam sebuahbash
shell tidak diperlukan karenabash
secara otomatis akan menggunakan$REPLY
variabel shell sebagai gantinya jika Anda tidak menentukan satu, tetapi POSIXly Anda harus selalu melakukannya. Saya senang Anda menemukannya berguna. semoga sukses dengan itu. im mikeserv @ gmail jika Anda membutuhkan sesuatu secara mendalam. saya harus memiliki komputer lagi dalam beberapa hariJawaban ini meminjam ide-ide dari jawaban lain ini dan jawaban lain ini tetapi dibangun di atasnya, menciptakan jawaban yang lebih umum berlaku:
Baris pertama menjalankan
sed
perintah dengan output ditulis ke output standar (dan bukan ke file); khusus, ke pipawc
untuk menghitung karakter. Baris kedua juga menjalankansed
perintah dengan keluaran ditulis ke keluaran standar, yang, dalam hal ini diarahkan ke file input dalam mode baca / tulis timpa (tanpa terpotong), yang dibahas di sini . Ini agak berbahaya untuk dilakukan; aman hanya ketika perintah filter tidak pernah meningkatkan jumlah data (teks); yaitu, untuk setiap n byte yang dibaca, ia menulis n atau lebih sedikit byte. Ini tentu saja berlaku untuksed '/myregex/d'
perintah; untuk setiap baris yang dibacanya, ia menulis baris yang sama persis, atau tidak sama sekali. (Contoh lain:s/foo/fu/
ataus/foo/bar/
akan aman, tetapis/fu/foo/
dans/foo/foobar/
tidak akan.)Sebagai contoh:
karena 32 byte data ini:
ditimpa dengan 25 karakter ini:
meninggalkan tujuh byte yang
night.\n
tersisa di akhir.Akhirnya,
dd
perintah mencari ke bagian akhir dari data yang baru digosok (byte 25 dalam contoh ini) dan menghapus sisa file; yaitu, itu memotong file pada saat itu.Jika, karena alasan apa pun,
1<>
triknya tidak berfungsi, Anda dapat melakukannyaJuga, perhatikan bahwa, selama semua yang Anda lakukan adalah menghapus garis, yang Anda butuhkan adalah
grep -v myregex
(seperti yang ditunjukkan oleh Barmar ).sumber
sed-i 'd' / path / ke / file / nama file
sumber