Mengapa Anda `cat / dev / null> / var / log / messages`?

77

Pada halaman contoh skrip bash ini , penulis menyajikan skrip ini:

# Cleanup
# Run as root, of course.

cd /var/log
cat /dev/null > messages
cat /dev/null > wtmp
echo "Log files cleaned up."

Mengapa Anda melakukan cat /dev/nullsesuatu? Saya tidak dapat mengerti apa yang dimaksudkan di sini (apakah itu menggunakan while TRUE; sleep 1; elihwuntuk {some busy program}?). Namun penulis menyebutnya "Tidak ada yang tidak biasa."

isomorfisma
sumber

Jawaban:

40

Anda biasanya cat /dev/null > [something]ketika ingin menghapus konten file sambil memastikan tidak ada risiko gangguan sama sekali terhadap status file yang sebenarnya. Isi file jelas akan dihapus oleh cat /dev/nullfile itu sendiri — sebagaimana adanya dan diketahui oleh sistem file tempat ia berada — akan tetap ada dengan nomor inode, kepemilikan, dan izin yang sama.

Dalam kasus file log, bisa jadi file log itu sendiri ditandai "sedang digunakan" oleh proses lain. Jadi, melakukan - misalnya - rm /var/log/messages && touch /var/log/messagesakan mengganggu proses lain dan dapat menyebabkan proses yang berjalan tersedak. Berarti suatu proses yang entah bagaimana dikunci ke nomor inode tertentu yang terhubung ke file /var/log/messagestiba-tiba bisa panik dan berkata, “Hei! Apa yang terjadi /var/log/messages! ”Bahkan jika file itu masih ada. Belum lagi masalah potensial dengan kepemilikan dan izin yang dibuat ulang secara tidak benar.

Karena ketidakpastian dalam penggunaan / keadaan file ini, penggunaan cat /dev/null > [something]lebih disukai oleh admin sistem yang ingin menghapus log tetapi tidak ingin berpotensi mengganggu operasi proses yang sudah ada.

Juga, dalam konteks halaman yang Anda tautkan ke penulis menyatakan sebagai berikut:

Tidak ada yang aneh di sini, hanya satu set perintah yang bisa dengan mudah dipanggil satu per satu dari baris perintah di konsol atau di jendela terminal. Keuntungan menempatkan perintah dalam skrip jauh melampaui tidak harus mengetik ulang mereka berkali-kali.

Jadi "tidak ada yang aneh" yang penulis sebutkan berkaitan dengan keseluruhan konsep tentang apa script bash spesifik itu: Itu hanya seperangkat perintah sederhana yang dapat dengan mudah dijalankan dari baris perintah tetapi ditempatkan dalam file teks untuk menghindari harus mengetik ulang mereka berulang kali.

JakeGould
sumber
10
@ jlliagre Satu-satunya hal yang "tetap hidup" adalah konteks pertanyaan yang difokuskan pada mengapa penulis asli akan melakukan itu. Jika Anda bersemangat untuk menghilangkan "mitos", silakan posting jawaban yang menyediakan konteks untuk metode pengkodean penulis asli serta perspektif tentang mengapa Anda percaya itu dapat diganti dengan metode lain.
JakeGould
7
@jlliagre jawaban Cyrus tidak menjawab pertanyaan inti mengapa penulis asli akan menggunakan metode itu atau alasan di baliknya. Tutorial yang disebutkan sudah cukup lama dan diterima dengan baik. Ini tidak salah dan juga tidak mengabadikan "legenda urban" yang seharusnya. Sebaliknya itu adalah cara kode satu orang versus cara kode orang lain. Sesimpel itu. Ini adalah masalah gaya yang tidak memiliki dampak negatif pada keandalan atau kinerja.
JakeGould
3
truncate -s 0akan melakukan hal yang sama dan tidak terlalu idiomatis. Namun, programmer shell adalah sekelompok konservatif dan orang mungkin menemukan sistem yang cukup tua atau cukup aneh sehingga tidak memiliki perintah itu.
Schwern
5
@skift cat /dev/null > /foo/barmemotong file; echo "" > /foo/barmemotongnya dan kemudian menulis satu karakter baris baru.
David
2
Keuntungan lain dari metode ini dibandingkan rm & touch adalah kepemilikan dan izin dipertahankan.
jjmontes
121

Mengapa Anda ingin / dev / null ke sesuatu?

Anda akan melakukan itu untuk memotong isi file sambil menjaga inode tetap utuh. Semua program yang membuka file untuk membaca atau menulis tidak akan terpengaruh di luar fakta ukuran file akan diatur ulang ke nol.

Alternatif palsu yang sering ditemukan adalah menghapus file kemudian membuatnya lagi:

rm file
touch file

atau yang serupa:

mv file file.old
gzip file.old
touch file

Masalahnya adalah metode ini tidak mencegah file lama dari terus ditulis oleh proses apa pun yang memiliki file yang dihapus terbuka pada waktu penghapusan. Alasan mengapa berada di bawah sistem file Unix, ketika Anda menghapus file, Anda hanya memutuskan tautan namanya (path) dari kontennya (inode). Inode tetap hidup selama ada proses yang terbuka untuk membaca atau menulis.

Ini menyebabkan beberapa efek negatif: log yang ditulis setelah penghapusan file hilang karena tidak ada cara mudah / portabel untuk membuka file yang dihapus. Selama proses menulis ke file yang dihapus, isinya masih menggunakan ruang pada sistem file. Itu berarti bahwa jika Anda menghapus / membuat file karena itu mengisi disk Anda, disk tetap terisi. Salah satu cara untuk memperbaiki masalah terakhir ini adalah memulai kembali proses logger tetapi Anda mungkin tidak ingin melakukannya karena layanan penting dan log perantara akan hilang secara definitif. Ada juga efek samping karena file yang Anda buat mungkin tidak memiliki izin, pemilik, dan grup yang sama dengan yang asli. Ini misalnya dapat mencegah penganalisa log untuk membaca file yang baru dibuat, atau lebih buruk, mencegah proses logging untuk menulis log sendiri.

Metode pertama, cat /dev/null > filemencapai tujuan dengan benar , meskipun memiliki legenda urban yang ulet, cat /dev/nullbagiannya sama sekali tidak berguna. Ini membuka file pseudo yang kosong oleh desain, gagal membaca apa pun dari itu dan akhirnya hanya keluar. Dengan menggunakan perintah ini maka buang-buang tombol, byte, panggilan sistem, dan siklus CPU dan dapat diganti tanpa perubahan fungsional dengan perintah no-op yang lebih cepat :atau bahkan, dengan sebagian besar shell, tanpa perintah sama sekali.

Biarkan saya mencoba metafora untuk menjelaskan betapa tidak berguna cat /dev/nullitu. Katakanlah tujuan Anda adalah mengosongkan gelas.

  • Anda pertama-tama mengeluarkan cairan apa pun darinya. Itu cukup dan tepat apa ( > file) tidak mengingat fakta pengalihan selalu diproses terlebih dahulu.

  • Kemudian, Anda mengambil botol kosong ( /dev/null) dan menuangkannya ke gelas kosong ( cat). Ini adalah langkah sia-sia ...

Jika Anda membaca dokumen tertaut Anda sampai akhir, Anda mungkin memperhatikan komentar di baris ini dari versi skrip yang disempurnakan:

    cat / dev / null> wtmp #   ':> wtmp' dan '> wtmp' memiliki efek yang sama.

Mereka memang punya; terlalu buruk cat /dev/nulldisimpan dalam kode.

Itu berarti bahwa kode berikut ini akan berfungsi dengan semua shell umum (baik cshdan shkeluarga):

cd /var/log
: > messages
: > wtmp
echo "Log files cleaned up."

dan ini akan bekerja dengan semua kerang menggunakan sintaks Bourne, seperti ash, bash, ksh, zshdan sejenisnya:

cd /var/log
> messages
> wtmp
echo "Log files cleaned up."

Perhatikan bahwa dengan shell Bourne pre-POSIX kuno, salah satu dari perintah ini, termasuk perintah cat /dev/nulltidak akan memotong file jika ditulis sesudahnya oleh skrip shell yang masih berjalan yang menambahkannya. Alih-alih file byte nol, itu akan menjadi file jarang dengan ukurannya tidak berubah. Hal yang sama akan terjadi jika file tersebut ditulis oleh suatu proses mencari ke posisi yang dianggapnya saat ini sebelum menulis.

Hati-hati juga bahwa beberapa solusi alternatif sering disarankan untuk memotong file yang memang memiliki kekurangan.

  • Kedua hal berikut ini tidak melakukan pekerjaan. File yang dihasilkan tidak kosong tetapi berisi baris kosong. Ini akan memecah file log seperti wtmpitu menyimpan catatan lebar tetap.

    echo > file
    echo "" > file
    
  • Yang berikutnya berdasarkan shopsi BSD tidak portabel, POSIX tidak menentukan opsi yang diizinkan untuk gema sehingga Anda mungkin berakhir dengan file yang berisi baris dengan " -n":

    echo -n > file
  • Yang itu juga tidak portabel dengan menggunakan shurutan pelarian System V. Beberapa shell akan membuat file yang berisi baris dengan " \c":

    echo "\c" > file
  • Yang itu menggunakan perintah yang dirancang untuk melakukan pekerjaan itu. Masalah yang digunakan truncatetidak portabel karena perintah ini, yang tidak ditentukan oleh POSIX, mungkin hilang dari sistem Unix / Linux.

    truncate -s 0

Akhirnya, berikut adalah beberapa alternatif yang portabel dan akan melakukan pekerjaan dengan baik:

  • Mencetak string kosong ke file secara eksplisit:

    printf "" > file
  • Menggunakan trueperintah yang sangat setara dengan no-op satu :meskipun lebih mudah dibaca:

    true > file
Jlliagre
sumber
1
@JonathanLeffler Saya percaya Ini adalah bagian dari semua cshimplementasi saat ini meskipun belum tentu didokumentasikan. Dari csh halaman manual Solaris : Null command. This command is interpreted, but performs no action.. Saya tidak menemukan hal yang sama di tcshhalaman manual atau yang asli BSD cshtetapi sintaks ini mungkin selalu berhasil.
jlliagre
6
Salah satu alasan untuk menulis cat /dev/nulladalah untuk membuat niat Anda eksplisit.
Davidmh
1
@ Davidvidh Itu masuk akal tetapi pernyataan Anda tidak menolak pemeriksaan fakta. Saya telah mengamati idiom shell ini selama beberapa dekade. Ketika saya memiliki kesempatan untuk bertanya kepada penulis alasan di balik itu, saya selalu mendapat teori tidak sehat tentang menggunakan /dev/nullcara yang efisien untuk menyuntikkan nol byte, lagi pula yang lebih dapat diandalkan daripada menggunakan :atau tidak sama sekali. Di halaman ini juga, jawaban Cyrus yang singkat tetapi langsung ke titik memiliki nol suara sedangkan JakeGould yang menentang fakta cat /dev/nulladalah no-op (lihat komentar kami) sudah memiliki setidaknya empat suara.
jlliagre
2
@ jlliagre, pengetahuan saya tentang shell cukup mendasar, jadi saya mungkin bukan target populasi terbaik; tapi telanjang >atau :tidak jelas. Saya setuju itu memalukan bahwa mitos telah diperbanyak karena penggunaannya.
Davidmh
4
@ Davidvidmh Jika Anda benar-benar menginginkan sesuatu yang eksplisit sebelum pengalihan, saya akan merekomendasikan printf "" > fileyang portabel (POSIX) dan ringan seperti yang sering diimplementasikan sebagai shell builtin.
jlliagre
6

Ini adalah cara rumit untuk membawa file ke ukuran nol.

cd /var/log
> messages
> wtmp
echo "Log files cleaned up."
Cyrus
sumber
Sintaks ini tidak akan berfungsi di setiap shell.
reinierpost
2
Benar. Pertanyaan hanya ditandai dengan "bash".
Cyrus
@reinierpost Ini akan bekerja di semua kerang Bourne-style, bukan? Jangan khawatir csh.
Barmar
: > messagesjuga berfungsi. :atau pilihan trueyang lebih jelas untuk perintah yang tidak mencetak apa pun dan mengembalikan true.
Peter Cordes
-3

Untuk memotong file yang terbuka. Ini setara, dan lebih mudah dipahami:

echo -n > /var/log/messages

(Ditambahkan -n untuk menghindari baris baru)

bbaassssiiee
sumber
3
Ini memang lebih bisa dipahami tetapi sayangnya tidak setara. Bahkan akan merusak fungsi seperti pada wtmpcase. Lihat jawaban saya yang diperbarui.
jlliagre
echo -n menghindari baris baru.
bbaassssiiee
6
Memang akan jika Anda yakin untuk menggunakan bash, -ndinyatakan tidak akan bekerja di semua cangkang Bourne.
jlliagre