Sudah diketahui bahwa perintah seperti ini:
cat filename | some_sed_command >filename
menghapus nama file, sebagai pengalihan output, dieksekusi sebelum perintah, menyebabkan nama file terpotong.
Seseorang dapat memecahkan masalah dengan cara berikut:
cat file | some_sed_command | tee file >/dev/null
tapi saya tidak yakin ini akan berhasil dalam hal apapun: apa yang terjadi jika file (dan hasil dari perintah sed) sangat besar? Bagaimana sistem operasi dapat menghindari menimpa beberapa konten yang masih belum dibaca? Saya melihat bahwa ada juga perintah spons yang harus bekerja dalam hal apapun: apakah itu "lebih aman" dari tee?
command-line
bash
tee
VeryHardCoder
sumber
sumber
Jawaban:
Tidak ada .
Kemungkinan
file
drop akan terpotong, tetapi tidak ada jaminancat file | some_sed_command | tee file >/dev/null
tidak akan terpotongfile
.Itu semua tergantung pada perintah mana yang diproses terlebih dahulu, sebagai lawan dari apa yang diharapkan, perintah dalam pipa tidak diproses dari kiri ke kanan . Tidak ada jaminan tentang perintah mana yang akan dipilih pertama, jadi orang mungkin juga menganggapnya sebagai dipilih secara acak dan tidak pernah bergantung pada shell tidak memilih yang menyinggung.
Karena peluang untuk perintah yang salah untuk dipilih pertama di antara tiga perintah lebih rendah daripada peluang untuk perintah yang melanggar untuk dipilih pertama di antara dua perintah, kecil kemungkinannya
file
akan dipotong, tetapi itu masih akan terjadi .script.sh
:Jadi jangan pernah gunakan sesuatu seperti
cat file | some_sed_command | tee file >/dev/null
. Gunakansponge
seperti yang disarankan Oli.Sebagai alternatif, untuk lingkungan yang lebih keras dan / atau file yang relatif kecil seseorang dapat menggunakan string di sini dan substitusi perintah untuk membaca file sebelum perintah apa pun dijalankan:
sumber
Untuk
sed
khusus, Anda dapat menggunakan nya-i
di tempat argumen. Itu hanya menyimpan kembali ke file yang dibuka, misalnya:Jika Anda ingin melakukan sesuatu yang lebih keren, dengan anggapan Anda melakukan lebih dari
sed
, ya, Anda dapat menyangga semuanya dengansponge
(darimoreutils
paket) yang akan "menyerap" semua stdin sebelum menulis ke file. Ini sepertitee
tetapi dengan fungsionalitas yang lebih sedikit. Namun untuk penggunaan dasar, ini merupakan pengganti drop-in:Apakah itu lebih aman? Pastinya. Ini mungkin memiliki batas melalui jadi jika Anda melakukan sesuatu yang kolosal (dan tidak dapat di-edit dengan sed), Anda mungkin ingin melakukan pengeditan untuk file kedua dan kemudian
mv
file itu kembali ke nama file asli. Itu harus atomik (jadi apa pun yang tergantung pada file-file ini tidak akan pecah jika mereka membutuhkan akses konstan).sumber
Anda dapat menggunakan Vim dalam mode Ex:
%
pilih semua baris!
Jalankan perintahx
Simpan dan keluarsumber
Oh, tetapi
sponge
bukan satu-satunya pilihan; Anda tidak harus mendapatkanmoreutils
untuk mendapatkan ini berfungsi dengan benar. Mekanisme apa pun akan berfungsi selama memenuhi dua persyaratan berikut:Anda lihat, masalah yang diketahui oleh OP adalah bahwa shell akan membuat semua file yang diperlukan untuk pipa untuk bekerja sebelum bahkan mulai menjalankan perintah dalam pipeline, jadi itu adalah shell yang benar-benar memotong file output (yang sayangnya juga merupakan file input) sebelum salah satu perintah bahkan memiliki kesempatan untuk memulai eksekusi.
Itu
tee
perintah tidak bekerja, meskipun itu memenuhi persyaratan pertama, karena tidak memenuhi persyaratan kedua: akan selalu membuat file output segera setelah mulai, jadi pada dasarnya seburuk menciptakan pipa langsung ke file output. (Ini sebenarnya lebih buruk, karena penggunaannya memperkenalkan penundaan acak non-deterministik sebelum file output terpotong, jadi Anda mungkin berpikir itu berfungsi, padahal sebenarnya tidak.)Jadi, yang kita butuhkan untuk menyelesaikan masalah ini adalah beberapa perintah yang akan buffer semua inputnya sebelum menghasilkan output, dan yang mampu menerima nama file output sebagai parameter, sehingga kita tidak perlu menyalurkan outputnya ke dalam file output. Salah satu perintah itu adalah
shuf
. Jadi, berikut ini akan mencapai hal yang sama dengan yangsponge
dilakukan:Bagian
--random-source=/dev/zero
trikshuf
melakukan hal itu tanpa melakukan pengocokan sama sekali, sehingga akan buffer input Anda tanpa mengubahnya.sumber