Peringatan tentang '>'
Pemula Unix yang baru belajar tentang pengalihan I / O ( <
dan >
) sering mencoba hal-hal seperti
command … input_file > the_same_file
atau
command ... < file > the_same_file
atau, hampir setara,
file kucing | command …> the_same_file
( grep
, sed
, cut
, sort
, Dan spell
adalah contoh perintah yang orang tergoda untuk digunakan dalam konstruksi seperti ini.) Pengguna terkejut menemukan bahwa skenario ini menghasilkan file menjadi kosong.
Sebuah nuansa yang tampaknya tidak disebutkan dalam jawaban lainnya dapat ditemukan bersembunyi dalam kalimat pertama dari Pengalihan bagian dari bash (1) :
Sebelum perintah dieksekusi, input dan outputnya dapat dialihkan
menggunakan notasi khusus yang ditafsirkan oleh shell.
Lima kata pertama harus tebal, miring, bergaris bawah, diperbesar, berkedip, berwarna merah, dan ditandai dengan ikon, untuk menekankan fakta bahwa shell melakukan pengalihan yang diminta
sebelum perintah dijalankan . Dan ingat juga
Pengalihan output menyebabkan file ... dibuka untuk ditulis .... Jika file tidak ada itu dibuat; jika memang ada itu dipotong ke ukuran nol.
Jadi, dalam contoh ini:
sort roster > roster
shell membuka roster
file untuk ditulis, memotongnya (yaitu, membuang semua isinya), sebelum sort
program mulai berjalan. Secara alami, tidak ada yang bisa dilakukan untuk memulihkan data.
Orang mungkin naif mengharapkan itu
tr "[:upper:]" "[:lower:]" < poem > poem
mungkin lebih baik. Karena shell menangani pengalihan dari kiri ke kanan, shell terbuka poem
untuk membaca (untuk tr
input standar) sebelum membukanya untuk menulis (untuk output standar). Tapi itu tidak membantu. Meskipun urutan operasi ini menghasilkan dua pegangan file, mereka berdua menunjuk ke file yang sama. Ketika shell membuka file untuk dibaca, isinya masih ada, tetapi mereka masih musnah sebelum program dieksekusi.
Jadi, apa yang harus dilakukan?
Solusi meliputi:
Periksa apakah program yang Anda jalankan memiliki kapabilitas sendiri, internal, untuk menentukan ke mana output berjalan. Ini sering ditunjukkan dengan token -o
(atau --output=
). Khususnya,
sort roster -o roster
kira-kira setara dengan
sort roster > roster
kecuali, dalam kasus pertama, sort
program membuka file output. Dan cukup pintar untuk tidak membuka file output sampai setelah membaca semua file input.
Demikian pula, setidaknya beberapa versi sed
memiliki -i
(edit i n tempat) pilihan yang dapat digunakan untuk menulis output kembali ke file input (sekali lagi, setelah semua masukan sudah dibaca). Editor seperti ed
/ ex
, emacs
, pico
, dan vi
/ vim
memungkinkan pengguna untuk mengedit file teks dan menyimpan teks diedit di file asli. Perhatikan bahwa ed
(setidaknya) dapat digunakan secara non-interaktif.
vi
memiliki fitur terkait. Jika Anda mengetik , itu akan menulis isi buffer edit , membaca hasilnya, dan memasukkannya ke buffer (mengganti konten asli).:%!command
Entercommand
Sederhana tetapi efektif:
perintah ... input_file > temp_file && mv temp_file input_file
Ini memiliki kelemahan bahwa, jika input_file
merupakan tautan, tautan itu (mungkin) akan digantikan oleh file terpisah. Juga, file baru akan dimiliki oleh Anda, dengan perlindungan default. Secara khusus, ini membawa risiko bahwa file tersebut pada akhirnya akan dapat dibaca dunia, bahkan jika aslinya input_file
tidak.
Variasi:
command … input_file > temp_file && cp temp_file input_file && rm temp_file
yang masih akan (berpotensi) meninggalkan temp_file
dunia terbaca. Bahkan lebih baik:
cp input_file temp_file && command … temp_file > input_file && rm temp_file
Ini mempertahankan status tautan, pemilik, dan mode (perlindungan) file, berpotensi dengan biaya dua kali lipat I / O. (Anda mungkin perlu menggunakan opsi suka -a
atau -p
aktif cp
untuk mengatakannya untuk mempertahankan atribut.)
command … input_file > temp_file &&
cp --attributes-only --preserve=all input_file temp_file &&
mv temp_file input_file
(dipecah menjadi baris terpisah hanya untuk keterbacaan) Ini mempertahankan mode file (dan, jika Anda root, pemilik), tetapi membuatnya dimiliki oleh Anda (jika Anda bukan root), dan menjadikannya baru, file terpisah.
Blog ini
("Di-tempat" mengedit file) menyarankan dan menjelaskan
{rm input_file && command …> input_file ; } < input_file
Ini mensyaratkan bahwa command
mampu memproses input standar (tetapi hampir semua filter dapat). Blog itu sendiri menyebut ini kludge berisiko dan mencegah penggunaannya. Dan ini juga akan membuat file baru yang terpisah (tidak terkait dengan apa pun), yang dimiliki oleh Anda dan dengan izin default.
Paket moreutils memiliki perintah yang disebut sponge
:
perintah ... input_file | spons the_same_file
Lihat jawaban ini untuk informasi lebih lanjut.
Inilah sesuatu yang mengejutkan saya:
sintaksis mengatakan :
[Sebagian besar solusi ini] akan gagal pada sistem file read-only, di mana "read-only" berarti bahwa Anda $HOME
akan dapat ditulis, tetapi /tmp
akan hanya-baca (secara default). Misalnya, jika Anda memiliki Ubuntu, dan Anda telah mem-boot ke Konsol Pemulihan, biasanya demikian. Juga, operator dokumen di sini <<<
tidak akan bekerja di sana, karena /tmp
harus dibaca / ditulis
karena akan menulis file sementara ke sana juga.
(lih. pertanyaan ini mencakup strace
keluaran d)
Berikut ini mungkin berfungsi dalam kasus itu:
Jadi, apa pertanyaannya?
Ini telah menjadi topik populer tentang U&L; itu dibahas dalam pertanyaan-pertanyaan berikut:
... dan itu tidak termasuk Super User atau Ask Ubuntu. Saya telah memasukkan banyak informasi dari jawaban atas pertanyaan di atas dalam jawaban ini, tetapi tidak semua. (Yaitu, untuk informasi lebih lanjut, baca pertanyaan-pertanyaan yang tercantum di atas dan jawabannya.)
PS Saya tidak memiliki afiliasi dengan blog yang saya kutip di atas.