Dalam shell, bagaimana saya bisa tail
membuat file terbaru dalam direktori?
linux
shell
shell-script
Itay Moav -Malimovka
sumber
sumber
Jawaban:
Jangan tidak mengurai output dari ls! Mengurai output ls sulit dan tidak dapat diandalkan .
Jika Anda harus melakukan ini, saya sarankan menggunakan find. Awalnya saya punya contoh sederhana di sini hanya untuk memberi Anda inti dari solusi, tetapi karena jawaban ini tampaknya agak populer saya memutuskan untuk merevisi ini untuk menyediakan versi yang aman untuk menyalin / menempel dan digunakan dengan semua input. Apakah Anda duduk dengan nyaman? Kami akan mulai dengan oneliner yang akan memberi Anda file terbaru di direktori saat ini:
Tidak cukup oneliner sekarang, kan? Ini dia lagi sebagai fungsi shell dan diformat untuk lebih mudah dibaca:
Dan sekarang bahwa sebagai oneliner sebuah:
Jika semuanya gagal, Anda dapat memasukkan fungsi di atas dalam
.bashrc
dan mempertimbangkan masalah terpecahkan, dengan satu peringatan. Jika Anda hanya ingin menyelesaikan pekerjaan, Anda tidak perlu membaca lebih lanjut.Peringatan dengan ini adalah bahwa nama file yang diakhiri dengan satu atau lebih baris baru masih tidak akan diteruskan dengan
tail
benar. Mengatasi masalah ini rumit dan saya menganggapnya cukup bahwa jika nama file berbahaya tersebut dijumpai, perilaku yang relatif aman untuk menemukan kesalahan "Tidak ada file seperti itu" akan terjadi alih-alih sesuatu yang lebih berbahaya.Detail juicy
Bagi yang penasaran ini adalah penjelasan yang melelahkan tentang cara kerjanya, mengapa ini aman dan mengapa metode lain mungkin tidak.
Bahaya, Will Robinson
Pertama-tama, satu-satunya byte yang aman untuk membatasi jalur file adalah nol karena itu adalah satu-satunya byte yang secara universal dilarang di jalur file pada sistem Unix. Penting ketika menangani daftar jalur file apa saja untuk hanya menggunakan null sebagai pembatas dan, ketika menyerahkan bahkan satu jalur file dari satu program ke program lain, untuk melakukannya dengan cara yang tidak akan tersedak byte acak. Ada banyak cara yang tampaknya benar untuk menyelesaikan masalah ini dan masalah lain yang gagal dengan mengasumsikan (bahkan tidak sengaja) bahwa nama file tidak akan memiliki baris atau spasi baru di dalamnya. Tidak ada asumsi yang aman.
Untuk keperluan hari ini, langkah pertama adalah mendapatkan daftar file tanpa batas yang tidak ditemukan. Ini sangat mudah jika Anda memiliki
find
pendukung-print0
seperti GNU:Tetapi daftar ini masih tidak memberi tahu kami mana yang terbaru, jadi kami perlu memasukkan informasi itu. Saya memilih untuk menggunakan
-printf
switch find yang memungkinkan saya menentukan data apa yang muncul di output. Tidak semua versifind
dukungan-printf
(ini bukan standar) tetapi GNU find tidak. Jika Anda menemukan diri-printf
Anda tanpa Anda harus mengandalkan pada-exec stat {} \;
titik mana Anda harus melepaskan semua harapan portabilitas karenastat
tidak standar juga. Untuk saat ini saya akan melanjutkan dengan asumsi Anda memiliki alat GNU.Di sini saya meminta format printf
%T@
yang merupakan waktu modifikasi dalam hitungan detik sejak awal zaman Unix diikuti oleh suatu periode dan kemudian diikuti oleh angka yang menunjukkan pecahan detik. Saya menambahkan ini periode lain dan kemudian%p
(yang merupakan path lengkap ke file) sebelum berakhir dengan byte nol.Sekarang sudah
Itu mungkin pergi tanpa mengatakan tetapi demi menjadi lengkap
-maxdepth 1
mencegahfind
dari daftar isi sub direktori dan\! -type d
melewatkan direktori yang Anda tidak ingintail
. Sejauh ini saya memiliki file di direktori saat ini dengan informasi waktu modifikasi, jadi sekarang saya perlu mengurutkan berdasarkan waktu modifikasi.Mendapatkannya dalam urutan yang benar
Secara default
sort
mengharapkan inputnya untuk menjadi catatan dibatasi-baris baru. Jika Anda memiliki GNU,sort
Anda dapat memintanya untuk mengharapkan catatan yang dibatasi-nol alih-alih dengan menggunakan-z
sakelar .; untuk standarsort
tidak ada solusi. Saya hanya tertarik untuk mengurutkan berdasarkan dua angka pertama (detik dan fraksi kedua) dan tidak ingin mengurutkan berdasarkan nama file yang sebenarnya jadi saya memberi tahusort
dua hal: Pertama, harus mempertimbangkan periode (.
) pembatas bidang dan kedua bahwa itu hanya harus menggunakan bidang pertama dan kedua ketika mempertimbangkan cara menyortir catatan.Pertama-tama saya menggabungkan tiga opsi pendek yang tidak memiliki nilai bersama;
-znr
hanyalah cara singkat untuk mengatakan-z -n -r
). Setelah itu-t .
(spasi opsional) memberi tahusort
karakter pembatas bidang dan-k 1,2
menentukan nomor bidang: pertama dan kedua (sort
menghitung bidang dari satu, bukan nol). Ingatlah bahwa catatan sampel untuk direktori saat ini akan terlihat seperti:Ini berarti
sort
akan terlihat pada awalnya1000000000
dan kemudian0000000000
ketika memesan catatan ini. The-n
pilihan memberitahusort
menggunakan perbandingan numerik ketika membandingkan nilai-nilai ini, karena kedua nilai adalah angka. Ini mungkin tidak penting karena angkanya panjang tetap tetapi tidak ada salahnya.Switch lain yang diberikan
sort
adalah-r
untuk "mundur." Secara default output dari jenis numerik akan menjadi angka terendah pertama,-r
mengubahnya sehingga daftar angka terendah lalu dan angka tertinggi pertama. Karena angka-angka ini adalah cap waktu yang lebih tinggi berarti lebih baru dan ini menempatkan catatan terbaru di awal daftar.Hanya bagian-bagian penting
Ketika daftar path file muncul dari
sort
sana sekarang memiliki jawaban yang diinginkan kami cari tepat di atas. Yang tersisa adalah menemukan cara untuk membuang catatan lain dan menghapus cap waktu. Sayangnya bahkan GNUhead
dantail
tidak menerima sakelar untuk membuatnya beroperasi pada input tanpa batas nol. Sebaliknya saya menggunakan loop sementara sebagai semacam orang miskinhead
.Pertama-tama saya menghapus
IFS
pengaturan sehingga daftar file tidak mengalami pemisahan kata. Berikutnya saya mengatakanread
dua hal: Jangan menginterpretasikan urutan escape pada input (-r
) dan input dibatasi dengan byte nol (-d
); di sini string kosong''
digunakan untuk menunjukkan "no delimiter" alias dibatasi oleh null. Setiap catatan akan dibaca ke dalam variabelrecord
sehingga setiap kaliwhile
loop berulang itu memiliki cap waktu tunggal dan nama file tunggal. Perhatikan bahwa itu-d
adalah ekstensi GNU; jika Anda hanya memiliki standarread
teknik ini tidak akan berhasil dan Anda memiliki sedikit bantuan.Kita tahu bahwa
record
variabel memiliki tiga bagian untuk itu, semua dibatasi oleh karakter titik. Dengan menggunakancut
utilitas, dimungkinkan untuk mengekstrak sebagian darinya.Di sini seluruh catatan dilewatkan ke
printf
dan dari sana disalurkan kecut
; di bash Anda bisa menyederhanakan ini lebih lanjut menggunakan disini tali untukcut -d. -3f- <<<"$record"
untuk kinerja yang lebih baik. Kami memberi tahucut
dua hal: Pertama dengan-d
itu harus pembatas khusus untuk mengidentifikasi bidang (seperti dengansort
pembatas.
digunakan). Keduacut
diperintahkan-f
untuk mencetak hanya nilai-nilai dari bidang tertentu; daftar bidang diberikan sebagai rentang3-
yang menunjukkan nilai dari bidang ketiga dan dari semua bidang berikut. Ini berarti bahwacut
akan membaca dan mengabaikan semuanya hingga dan termasuk yang kedua.
yang ditemukan dalam catatan dan kemudian akan mencetak sisanya, yang merupakan bagian path file.Setelah mencetak path file terbaru, Anda tidak perlu melanjutkan:
break
keluar dari loop tanpa membiarkannya pindah ke path file kedua.Satu-satunya yang tersisa adalah berjalan
tail
di jalur file yang dikembalikan oleh pipa ini. Anda mungkin telah memperhatikan dalam contoh saya bahwa saya melakukan ini dengan melampirkan pipa dalam sebuah subkulit; apa yang Anda mungkin tidak perhatikan adalah bahwa saya melampirkan subkulit dalam tanda kutip ganda. Ini penting karena pada akhirnya bahkan dengan semua upaya ini agar aman untuk setiap nama file, perluasan subkulit yang tidak dikutip masih dapat merusak banyak hal. Penjelasan lebih rinci tersedia jika Anda tertarik. Aspek penting kedua tetapi mudah diabaikan untuk doatail
adalah bahwa saya memberikan pilihan--
untuk itu sebelum memperluas nama file. Ini akan menginstruksikantail
bahwa tidak ada lagi opsi yang ditentukan dan semuanya berikut adalah nama file, yang membuatnya aman untuk menangani nama file yang dimulai dengan-
.sumber
tail -f $(find . -type f -exec stat -f "%m {}" {} \;| sort -n | tail -n 1 | cut -d ' ' -f 2)
head
dantail
tidak menerima sakelar untuk membuatnya beroperasi pada input tanpa batas nol." Pengganti saya untukhead
:… | grep -zm <number> ""
.Jika Anda khawatir tentang nama file dengan spasi,
sumber
Kamu bisa memakai:
The
$()
membangun dimulai sub-shell yang menjalankan perintahls -1t
(daftar semua file dalam urutan waktu, satu per baris) dan pipa yang melaluihead -1
untuk mendapatkan baris pertama (file).Output dari perintah itu (file terbaru) kemudian diteruskan ke
tail
untuk diproses.Ingatlah bahwa ini berisiko mengambil direktori jika itu adalah entri direktori terbaru yang dibuat. Saya telah menggunakan trik itu dalam alias untuk mengedit file log terbaru (dari set yang berputar) di direktori yang hanya berisi file-file log tersebut.
sumber
-1
perlu,ls
apakah itu untuk Anda ketika ada di pipa. Bandingkanls
danls|cat
, misalnya.Pada sistem POSIX, tidak ada cara untuk mendapatkan entri direktori "yang terakhir dibuat". Setiap entri direktori memiliki
atime
,mtime
danctime
, tetapi bertentangan dengan Microsoft Windows,ctime
bukan berarti CreationTime, tetapi "Waktu perubahan status terakhir".Jadi yang terbaik yang bisa Anda dapatkan adalah "mengekor file yang terakhir diubah", yang dijelaskan dalam jawaban lain. Saya akan pergi untuk perintah ini:
Perhatikan kutipan di sekitar
ls
perintah. Ini membuat snippet bekerja dengan hampir semua nama file.sumber
Saya hanya ingin melihat perubahan ukuran file yang dapat Anda gunakan menonton.
sumber
Dalam
zsh
:Lihat: http://zsh.sourceforge.net/Doc/Release/Expansion.html#Glob-Qualifiers , di sini
m
menunjukkan waktu modifikasim[Mwhms][-|+]n
, dan sebelumnya menunjukkano
bahwa ia diurutkan dalam satu cara (O
mengurutkannya dengan cara lain). The.
berarti hanya file biasa. Di dalam kurung[1]
mengambil item pertama. Untuk memilih tiga digunakan[1,3]
, untuk mendapatkan penggunaan tertua[-1]
.Itu bagus pendek dan tidak digunakan
ls
.sumber
Mungkin ada sejuta cara untuk melakukan ini, tetapi cara saya akan melakukannya adalah ini:
Bit antara backticks (kutipan seperti karakter) ditafsirkan dan hasilnya dikembalikan ke ekor.
sumber
Sederhana:
bekerja dengan baik untuk saya.
Masalahnya adalah untuk mendapatkan file yang dihasilkan setelah Anda memulai perintah ekor. Tetapi jika Anda tidak membutuhkannya (karena semua solusi di atas tidak mempedulikannya), tanda bintang hanyalah solusi yang lebih sederhana, IMO.
sumber
sumber
Seseorang mempostingnya, dan kemudian menghapusnya karena suatu alasan, tetapi ini adalah satu-satunya yang berfungsi, jadi ...
sumber
ls
bukan hal yang paling cerdas untuk dilakukan ...Penjelasan:
sumber
sumber