Saya memiliki direktori yang berisi file dengan nama seperti logXX
di mana XX adalah angka heksa huruf besar dua karakter, nol empuk, seperti:
log00
log01
log02
...
log0A
log0B
log0C
...
log4E
log4F
log50
...
Umumnya akan ada kurang dari 20 atau 30 file total. Tanggal dan waktu pada sistem khusus saya bukanlah sesuatu yang dapat diandalkan (sistem tertanam tanpa sumber waktu NTP atau GPS yang dapat diandalkan). Namun nama file akan meningkat secara andal seperti yang ditunjukkan di atas.
Saya ingin grep
melalui semua file untuk satu entri log terbaru dari jenis tertentu, saya berharap untuk cat
file bersama-sama seperti…
cat /tmp/logs/log* | grep 'WARNING 07 -' | tail -n1
Namun terpikir oleh saya bahwa versi bash
yang berbeda atau sh
atau zsh
dll. mungkin memiliki ide yang berbeda tentang bagaimana *
diperluas.
man bash
halaman tidak mengatakan apakah perluasan *
akan menjadi daftar abjad yang pasti dari nama file yang cocok. Tampaknya meningkat setiap kali saya mencobanya di semua sistem yang tersedia untuk saya — tetapi apakah itu perilaku DEFINED atau hanya implementasi tertentu?
Dengan kata lain, bisakah saya benar-benar mengandalkan cat /tmp/logs/log*
untuk menggabungkan semua file log saya dalam urutan abjad?
Jawaban yang Diterima:
Di semua shell, gumpalan diurutkan secara default. Mereka sudah di bawah /etc/glob
helper yang dipanggil oleh shell Ken Thompson untuk memperluas gumpalan di versi pertama Unix di awal 70-an (dan yang memberi nama gumpalan).
Untuk sh
, POSIX memang mengharuskan mereka untuk diurutkan dengan cara strcoll()
, yaitu menggunakan urutan pengurutan di lokal pengguna, seperti untuk ls
meskipun beberapa masih melakukannya melalui strcmp()
, yang didasarkan pada nilai byte saja.
$ dash -c 'echo *'
Log01B log-0D log00 log01 log02 log0A log0B log0C log4E log4F log50 log① log② lóg01
$ bash -c 'echo *'
log① log② log00 log01 lóg01 Log01B log02 log0A log0B log0C log-0D log4E log4F log50
$ zsh -c 'echo *'
log① log② log00 log01 lóg01 Log01B log02 log0A log0B log0C log-0D log4E log4F log50
$ ls
log② log① log00 log01 lóg01 Log01B log02 log0A log0B log0C log-0D log4E log4F log50
$ ls | sort
log②
log①
log00
log01
lóg01
Log01B
log02
log0A
log0B
log0C
log-0D
log4E
log4F
log50
Anda mungkin memperhatikan di atas bahwa untuk shell yang melakukan penyortiran berdasarkan lokal, di sini pada sistem GNU dengan en_GB.UTF-8
lokal, -
dalam nama file diabaikan untuk penyortiran (sebagian besar karakter tanda baca akan). ó
diurutkan dengan cara yang lebih diharapkan (setidaknya untuk orang Inggris), dan kasus diabaikan (kecuali untuk memutuskan ikatan).
Namun, Anda akan melihat beberapa inkonsistensi untuk log① log②. Itu karena urutan pengurutan dan tidak ditentukan di lokal GNU (saat ini; mudah-mudahan akan diperbaiki suatu hari nanti). Mereka mengurutkan sama, sehingga Anda mendapatkan hasil acak.
Terkait:Proses keturunan?
Mengubah lokal akan mempengaruhi urutan penyortiran. Anda dapat mengatur lokal ke C untuk mendapatkan strcmp()
-pengurutan seperti:
$ bash -c 'echo *'
log① log② log00 log01 lóg01 Log01B log02 log0.2 log0A log0B log0C log-0D log4E log4F log50
$ bash -c 'LC_ALL=C; echo *'
Log01B log-0D log0.2 log00 log01 log02 log0A log0B log0C log4E log4F log50 log① log② lóg01
Perhatikan bahwa beberapa lokal dapat menyebabkan beberapa kebingungan bahkan untuk semua-ASCII semua-alnum string. Seperti yang Ceko (setidaknya pada sistem GNU) di mana ch
adalah elemen penyusunan yang diurutkan setelah h
:
$ LC_ALL=cs_CZ.UTF-8 bash -c 'echo *'
log0Ah log0Bh log0Dh log0Ch
Atau, seperti yang ditunjukkan oleh @ninjalj, yang lebih aneh lagi di bahasa Hongaria:
$ LC_ALL=hu_HU.UTF-8 bash -c 'echo *'
logX LOGx LOGX logZ LOGz LOGZ logY LOGY LOGy
Dalam zsh
, Anda dapat memilih pengurutan dengan kualifikasi glob. Misalnya:
echo *(om) # to sort by modification time
echo *(oL) # to sort by size
echo *(On) # for a *reverse* sort by name
echo *(o+myfunction) # sort using a user-defined function
echo *(N) # to NOT sort
echo *(n) # sort by name, but numerically, and so on.
Jenis numerik echo *(n)
juga dapat diaktifkan secara global dengan numericglobsort
pilihan:
$ zsh -c 'echo *'
log① log② log00 log01 lóg01 Log01B log02 log0.2 log0A log0B log0C log-0D log4E log4F log50
$ zsh -o numericglobsort -c 'echo *'
log① log② log00 lóg01 Log01B log0.2 log0A log0B log0C log01 log02 log-0D log4E log4F log50
Jika Anda (seperti saya) bingung dengan urutan itu dalam contoh tertentu (di sini menggunakan bahasa Inggris saya), lihat di sini untuk detailnya.