GNU/Linux >> Belajar Linux >  >> Linux

Apakah The Bash Star * Wildcard Selalu Menghasilkan Daftar Terurut (naik)?

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.


Linux
  1. Menyesuaikan shell Bash

  2. Perintah "eval" Di Bash?

  3. Tujuan .bashrc Dan Bagaimana Cara Kerjanya?

  1. Basa'?

  2. Bagaimana Cara Menyesuaikan Bash Autocomplete Untuk Mencantumkan File Di Direktori Lain?

  3. Bagaimana cara mendaftar ukuran setiap file dan direktori dan mengurutkan berdasarkan ukuran menurun di Bash?

  1. Apakah ~ Selalu Sama dengan $home?

  2. Apa yang dilakukan 'bash -c'?

  3. Apakah ada cara untuk mengatur ukuran daftar riwayat di bash menjadi lebih dari 5000 baris?