Bash yıldızı * joker karakteri her zaman (artan) sıralanmış bir liste oluşturur mu?


53

logXXXX gibi iki karakterli, sıfır dolgulu, büyük harfli onaltılık sayı gibi adlara sahip dosyalarla dolu bir dizin var :

log00
log01
log02
...
log0A
log0B
log0C
...
log4E
log4F
log50
...

Genellikle toplam 20 veya 30 dosyadan daha az olacaktır. Özel sistemimdeki tarih ve saat, güvenilebilecek bir şey değildir (güvenilir bir NTP veya GPS zaman kaynağı bulunmayan gömülü bir sistem). Ancak, dosya adları yukarıda gösterildiği gibi güvenilir bir şekilde artacaktır.

Ben isteyen grepbelirli bir türdeki tek ve en yeni günlük giriş için tüm dosyaları gezinirken ben umut oldu catgibi dosyaları bir araya ...

cat /tmp/logs/log* | grep 'WARNING 07 -' | tail -n1

Ancak bana bu farklı versiyonlarını meydana bashveya shveya zshnasıl farklı fikirlere sahip olabilir vs. *genişletilir.

man bashSayfa genişlemesi olsun veya olmasın demiyor *eşleşen dosya isimlerinin yazıldığı kesinlikle yükselen alfabetik liste olurdu. Ne zaman elimde olan tüm sistemlerde denedim, her defasında yükseliyor gibi görünüyor - ama bu TANIMLI davranış mı, yoksa sadece uygulamaya mı özgü?

Başka bir deyişle, cat /tmp/logs/log*tüm günlük dosyalarımı alfabetik sırayla birleştirmek için kesinlikle güvenebilir miyim ?


1
@ ADDB Varsayılan sıralama düzeni sort, bir dosya adı globbing desenini genişletirken kabuk ile aynıdır.
Kusalananda

9
Bu korkunç bir dosya adlandırma uygulaması. Koşunuza neden log (0) = - infty ile başlıyorsunuz?
EP,

14
@ EP Dosya sistemimiz, inode gerçeküstü numaralandırmalı, karmaşık 7 boyutlu bir hiper-toroiddir.
Meşgul kutunun

1
Sen önleyebilirsiniz catile grep -h pattern /tmp/logs/log*maçlara dosya prepending bastırmak için. (En azından GNU grep ile POSIX veya meşgul kutusunu kontrol etmedim.)
Peter Cordes

1
@Kusalananda Yararsız kullanım olduğunu duydunuz cat, bu yararsız kullanımsort
kedi

Yanıtlar:


52

Tüm kabuklarda, globler varsayılan olarak sıralanır. Onlar zaten,/etc/glob 70'li yılların başında (ve globlara isimlerini veren) Unix'in ilk versiyonunda globları genişletmek için Ken Thompson'ın kabuğunun çağırdığı yardımcınızdı .

Çünkü shPOSIX strcoll(), kullanıcı tarafından yerel ayarlarda sıralama düzenini kullanarak, yalnızca lshala strcmp()byte değerlerine dayanan, yine de bazılarının yaptığı gibi, sıralama yapmalarını gerektirir .

$ 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

Bir bir GNU sistemi burada, yerel ayara dayalı sıralama yapmak o kabuklar için yukarıda görebilirsiniz en_GB.UTF-8yerel ayarı, -dosya adlarında (olur Çoğu noktalama işaretini) sıralamak için yok sayılır. ó(En azından İngiliz halkına) daha beklenen şekilde sıralanır ve dava (bağlarını karar geldiğinde hariç) göz ardı edilir.

Ancak, log① log① için bazı tutarsızlıklar göreceksiniz. Bunun nedeni, ① ve the 'nın sıralama düzeninin GNU yerellerinde tanımlanmamış olmasıdır (şu anda; umarım bir gün sabitlenir). Aynısını sıralarlar, böylece rastgele sonuçlar elde edersiniz.

Yerel ayarların değiştirilmesi sıralama düzenini etkiler. strcmp()Benzer bir sıralama elde etmek için yerel ayarı C olarak ayarlayabilirsiniz :

$ 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

Bazı yerel ayarların, tüm ASCII alnum dizeleri için bile bazı kafa karışıklıklarına neden olabileceğini unutmayın. Çekliler gibi (en azından GNU sistemlerinde) chaşağıdakileri sıralayan bir harmanlama öğesinin bulunduğu yer h:

$ LC_ALL=cs_CZ.UTF-8 bash -c 'echo *'
log0Ah log0Bh log0Dh log0Ch

Ya da, @ ninjalj'ın belirttiği gibi, Macar yerlerinde tuhaf olanlar bile:

$ LC_ALL=hu_HU.UTF-8 bash -c 'echo *'
logX LOGx LOGX logZ LOGz LOGZ logY LOGY LOGy

İçinde zsh, glob niteleyicileri ile sıralamayı seçebilirsiniz . Örneğin:

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.

Sayısal tür seçeneği echo *(n), aşağıdaki numericglobsortseçeneklerle genel olarak da etkinleştirilebilir :

$ 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

Siz (olduğum gibi) bu sırada (buradaki İngiliz yerel ayarımı kullanarak) söz konusu sırayla karıştıysanız, ayrıntılar için buraya bakın.


1
'Ch' durumu daha da tuhaf olabilir: bazı yerler 'ch', 'Ch' ve 'CH' nin her birinin 1 harmanlama elemanı olduğuna karar verirken, 'cH' iki harmanlama öğesidir. Bakınız: unicode.org/cldr/trac/ticket/889 Mevcut CLDR tamamen tutarlı görünmüyor: mevcut Macarca ( unicode.org/cldr/trac/browser/trunk/common/collation/hu.xml ) gibi kurallara sahip &C<cs<<<Cs<<<CS, &C<cs<<<cS<<<Cs<<<CSönerilen bir deneysel taslak olarak işaretlenir. CLDR'ye içe aktarılan bazı eski verilerden yola çıkarak, eski AIX ve MS "küçük harf sonra büyük harf 2 farklı harmanlama öğesidir" görünümünü tercih ediyor gibiydi.
ninjalj

Ve yine de çalışmadığı sistemler gördüm. :(
Joshua

38

Bash için man sayfası şunları belirtir:

Pathname Genişletme

Sürece kelimesi yarma sonra, -fseçenek ayarlandığında, bash karakterleri için her kelimeyi tarar *, ?ve [. Bu karakterlerden biri belirirse, kelime bir kalıp olarak kabul edilir ve onun yerine alfabetik olarak sıralanmış bir dosya listesi listesi […] verilir.


1
Sadece macun veya manmetin oluşturma işleminde ilginç bir hata buldum ... aradığım metin "sarılı" kelimesini alırsa, o zaman bir / search komutu bulamaz. Sadece terminalimi en üst düzeye çıkardım ve orada :)
Wossname

2
Sen kapladın bash. Tho OP ayrıca "zsh vs." ile de ilgilendi.
Kusalananda

29

Bazı mermilerde çok özel bazı kabuk seçeneklerini tetiklemediğiniz sürece, çıktının aynı olması garanti edilir.

Sipariş POSIX standardında belirtilmiştir :

Desen, varolan herhangi bir dosya adı veya yol adıyla eşleşirse, model , geçerli yerel ayarda geçerli olan harmanlama sırasına göre sıralanmış , bu dosya adları ve yol adları ile değiştirilir . Bu harmanlama sırasının tüm karakterlerin toplam sıralaması yoksa (bkz. XBD LC_COLLATE), eşit şekilde harmanlanan dosya adları veya yol adları, POSIX yerel ayarı için harmanlama sırasını kullanarak bayt baytlarıyla karşılaştırılmalıdır.

Ayrıca bkz . POSIX Yerel Ayarındaki LC_COLLATE Kategorisi, kısaca eğer LC_COLLATE=Cişler ASCII sırayla sipariş edilirse .


bashkılavuzu söz

LC_COLLATE

Bu değişken, yol adı genişletme sonuçlarını sıralarken kullanılan harmanlama sırasını ve aralık ifadeleri, denklik sınıfları ve yol adı genişletme ve desen eşleştirme içindeki harmanlama sırasının davranışını belirler.

ksh93ve zshbenzer bir ifadeye sahip, bu konuda POSIX standardını takip ettiklerine inanmamı sağlıyor.

Diğer kabuklar, dosya adının toplanmasından kaynaklanan dosya adlarının sıralanması hakkında hiçbir şey söylemez pdkshve dashsöylemez. Bunun, en azından POSIX yerel ayarını kullanırken hala aynı standarda bağlı oldukları anlamına geldiğine inanıyorum. Deneyimlerime göre, ASCII dosya adlarının açık bir şekilde "garip" sıralamasını yapan bir kabukla karşılaşmadım.


2
Sıralamayı etkileyebilecek numericglobsortseçeneğe bakın zsh. Yine de, echo *(n)bu seçeneği küresel olarak açmak yerine, dünya çapında bir şekilde etkinleştirmeyi tercih ederim .
Stéphane Chazelas

Bir nitpick. Bash, varsayılan modda, Posix uyumlu DEĞİLDİR.
fpmurphy

@ fpmurphy1 Daha fazlasını söyle.
Kusalananda

@Kusalananda. Bash hiçbir zaman POSIX şikayeti olarak onaylanmadı. Bash’de "POSIX-uyumluluk" almak için, Bash’i --posixkomut satırı seçeneğiyle çağırmanız veya çalıştırmanız gerekirset -o posix
fpmurphy

@ fpmurphy1 Evet, ancak dosya adı globbing karakterlerinin genişlemesinin sıralaması Bash'in posixmodundan etkilenmiyor . Bkz. Gnu.org/software/bash/manual/html_node/Bash-POSIX-Mode.html Bu, sıralamanın POSIX uyumlu olduğuna inanmamı (umarım) sağlar.
Kusalananda

1

Birincil hedef, girdi dosyalarını yaşlarına göre sıralamaksa, en eskisi önce

(cd /tmp/logs; cat `ls -rt log*`) | grep whatever

Ve eğer döndürülmüş ve sıkıştırılmış kütükler de dahil edilmişse:

(cd /tmp/logs; zcat -f `ls -rt log*`) | grep whatever

4
Dosyaların zaman damgalarına güvenilmemesi gerektiği belirtildi.
Kusalananda

3
@Kusalananda, doğru, sistem zamanımız genellikle rastgele bir sayı üreteci olarak kabul edilir :)
Wossname
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.