Mengapa mengarahkan ulang output file ke dirinya sendiri menghasilkan file kosong?
Dinyatakan dalam Bash, mengapa
less foo.txt > foo.txt
dan
fold foo.txt > foo.txt
menghasilkan yang kosong foo.txt
? Karena append seperti less eggs.py >> eggs.py
menghasilkan dua salinan teks eggs.py
, seseorang mungkin berharap bahwa overwrite akan menghasilkan satu salinan teks.
Catatan, saya tidak mengatakan ini adalah bug, itu lebih cenderung penunjuk sesuatu yang mendalam tentang Unix.
bash
unix
unix-utils
seewalker
sumber
sumber
Jawaban:
Ketika Anda menggunakan
>
, file dibuka dalam mode pemotongan sehingga isinya dihapus sebelum perintah mencoba untuk membacanya.Saat Anda menggunakan
>>
, file dibuka dalam mode tambahkan sehingga data yang ada dipertahankan. Namun masih cukup berisiko untuk menggunakan file yang sama dengan input dan output dalam kasus ini. Jika file cukup besar agar tidak sesuai dengan ukuran buffer input baca, ukurannya mungkin tumbuh tanpa batas hingga sistem file penuh (atau kuota disk Anda tercapai).Jika Anda ingin menggunakan file sebagai input dan output dengan perintah yang tidak mendukung modifikasi tempat, Anda dapat menggunakan beberapa solusi:
Gunakan file perantara dan timpa yang asli ketika selesai dan hanya jika tidak ada kesalahan terjadi saat menjalankan utilitas (ini adalah cara paling aman dan lebih umum).
Hindari file perantara dengan mengorbankan potensi hilangnya sebagian atau seluruh data jika terjadi kesalahan atau gangguan. Dalam contoh ini, konten
foo.txt
dilewatkan sebagai input ke subkulit (di dalam tanda kurung) sebelum file dihapus. Inode sebelumnya tetap hidup karena subshell tetap terbuka saat membaca data. File yang ditulis oleh utilitas dalam (di sinifold
) sambil memiliki nama yang sama (foo.txt
) menunjuk ke inode yang berbeda karena entri direktori lama telah dihapus secara teknis, ada dua "file" berbeda dengan nama yang sama selama proses. Ketika subkulit berakhir, inode lama dilepaskan dan datanya hilang. Berhati-hatilah untuk memastikan Anda memiliki cukup ruang untuk menyimpan sementara file lama dan yang baru pada saat yang sama jika tidak Anda akan kehilangan data.sumber
sponge
dari moreutils juga dapat membantu.fold foo.txt | sponge foo.txt
- ataufold foo.txt | sponge !$
juga harus dilakukan.File dibuka untuk ditulis oleh shell sebelum aplikasi memiliki kesempatan untuk membacanya. Membuka file untuk menulis memotongnya.
sumber
Dalam bash, operator redirection aliran
... > foo.txt
mengosongkanfoo.txt
sebelum mengevaluasi operan kiri .Seseorang dapat menggunakan substitusi perintah dan mencetak hasilnya sebagai solusi. Solusi ini mengambil lebih sedikit karakter tambahan daripada di jawaban lain:
Hati-hati: Perintah ini tidak mempertahankan baris baru yang sedang berjalan di
foo.txt
. Lihat bagian komentar di bawah untuk informasi lebih lanjutDi sini, subkulit
$(...)
dievaluasi sebelum operator pengalihan aliran>
, maka pelestarian informasi.sumber
tmp=$(cmd; printf q); printf '%s' "${tmp%q}"
. Tapi Anda melewatkan masalah lain dengan jawaban ini: ia mengatakan "subkulit" ketika itu berarti "substitusi perintah". Ya, pergantian perintah umumnya subkulit, tetapi bukan sebaliknya, dan subkulit, secara umum, tidak membantu untuk masalah ini.