POSIX sh'de -nt / -ot testi yapma


11

Yerleşik testve [yardımcı programlar var -nt( "daha yeni") ve -otaynı isimlerin dış programlar için geçerlidir da (kabuk "POSIX modunda" çalışması sırasında bile, çoğu kabuklarda ( "daha eski") testleri erişebildiğim sistemler). Bu testler, iki dosyadaki değişiklik zaman damgalarını karşılaştırmak içindir. Belgelendirilmiş semantikleri uygulamalar arasında biraz değişiklik gösterir (bir dosya veya başka bir dosya yoksa ne olacağı ile ilgili olarak), ancak POSIX spesifikasyonunatest dahil edilmezler . için yarar .

Bunlar taşınmadığı edildi testbunlar dahil edilmemiştir, çünkü koşullu komut [KornShell] kabuğundan çıkarılmış yardımcı testtarihsel uygulamaları yerleşik yardımcı shprogramı.

Bir /bin/shkabuk komut dosyasındaki dosyalar arasındaki değişiklik zaman damgasını karşılaştırmak ve sonra bir dosyanın diğerinden daha yeni olup olmadığına bağlı olarak işlem yapmak istediğimi varsayarsak

if [ "$sigfile"     -nt "$timestamp" ] ||
   [ "$sigfile.tmp" -nt "$timestamp" ]
then
    return
fi

... başka hangi yardımcı programı da kullanabilirim make(betiğin geri kalanını en azını söylemeye yaramaz)? Yoksa hiç kimsenin senaryoyu "tarihsel uygulaması" üzerinde çalıştırmayacağını shveya belirli bir kabuk için yazmaya istifa etmeyeceğini bashmi varsaymalıyım ?


Cevabımda görebileceğiniz gibi, bash -ntözelliğini testyakl. 1995. Doğru davranışı findsevseniz bile basd ifadesini kullanmalısınız bash.
schily

Yanıtlar:


10

POSIXLY:

f1=/path/to/file_1
f2=/path/to/file_2

if [ -n "$(find -L "$f1" -prune -newer "$f2")" ]; then
    printf '%s is newer than %s\n' "$f1" "$f2"
fi

Dosya adında yanlış pozitif oluşmasını önlemek için dosyalara mutlak yol kullanılması yalnızca satırsonu içerir.

Göreli yol kullanılıyorsa, findkomutu şu şekilde değiştirin :

find -L "$f1" -prune -newer "$f2" -exec echo . \;

teknik olarak, $f1sadece yeni satırlar içeriyorsa başarısız olduğunu düşünüyorum ;)
ilkkachu

1
@ilkkachu ile çalışabilir -exec echo x \;veya benzeri olabilir?
muru

@muru, evet. -printfstandart olsaydı kolay olurdu
ilkkachu

3
@Kusalananda AFAICT, find'in çıkış durumu, münferit finddönüş testlerinden bağımsızdır - belki de bu testleri yürütürken bir hata olması dışında. finddosya bulunmasa bile 0'dan çıkar.
muru

1
Davranışın [ / -nt /nofile ]uygulamaya bağlı olarak değiştiğini (ancak hiçbir zaman hata vermediğini) unutmayın.
Stéphane Chazelas

7

Bu, en eski Unix komutlarından birini kullanmak için bir durum olabilir ls.

x=$(ls -tdL -- "$a" "$b")
[ "$x" = "$a
$b" ]

A, b'den yeni ise sonuç doğrudur.


3
Dosya adları ile başlıyorsa -(eksik --) bu işe yaramaz . Sen gerekiyordu -Lo eşdeğer olduğu için -nt. Yani karşılaştırmak çalışmaz xve $'x\nx'mesela.
Stéphane Chazelas

1
Eek! Ama aynı zamanda ha.
Kusalananda

4

İlginç bir soru sordunuz ve önce doğrulanması gereken bir iddiada bulundunuz.

Ben davranışını kontrol ettim:

$shell -c '[ Makefile -nt SCCS/s.Makefile ] && echo newer'

çeşitli kabukları ile. Sonuçlar burada:

  • bash Çalışmıyor - hiçbir şey yazdırmıyor.

  • bosh çalışır

  • tire Çalışmıyor - hiçbir şey yazdırmıyor.

  • ksh88 Çalışmıyor - hiçbir şey yazdırmıyor.

  • ksh93 çalışır

  • mksh Çalışmıyor - hiçbir şey yazdırmıyor.

  • lüks baskılar: lüks: [: -nt: beklenmedik operatör / işlenen

  • yash çalışır

  • zsh yeni sürümlerde çalışır , eski sürümler hiçbir şey yazdırmaz

Dokuz mermiden dördü -nt özelliğini destekler ve doğru şekilde uygular. Bu durumda doğru: şu anlama gelir: ikinci zaman altı zaman damgası ayrıntı düzeyini destekleyen son platformlardaki zaman damgalarını karşılaştırabilir . Seçtiğim dosyaların zaman damgalarında genellikle birkaç mikrosaniye farklılık gösterdiğini unutmayın.

Çalışan bir finduygulama bulmak daha kolay olduğu için,

if [ "$file1" -nt "$file2" ] ; then
    echo newer
fi

bir yan findgöre ifade.

if [ "$( find "$file1" -newer "$file2" )" ]; then
    echo newer
fi

en azından $file1sadece satırsonu içermediği sürece çalışır .

if [ "$( find -L "$file1" -newer "$file2" -exec echo newer \; )" ]; then
    echo newer
fi

biraz yavaş ama düzgün çalışıyor.

BTW: Marka ile ilgili olarak tüm marka uygulamaları için konuşamıyorum, ancak SunPro Makeyaklaşık olarak nanosaniye tanecikliğiyle zaman karşılaştırmasını destekliyor. 20 yıl smakeve gmakeson zamanlarda bu özelliği ekledi.


1
"Çalışmayan" testler, ikinci saniye zaman damgalarını (kesinlikle?) Karşılaştıramadığından veya başka bir şeyden dolayı çalışmıyor mu? Testinize dahil olan dosyalardaki gerçek zaman damgaları nedir? Test için +1!
Kusalananda

2
Bence bu düşüş muhtemelen çatışmacı ifadelerle ilgili. Burada, bir sınırlama (bazı bağlamlarda önemli) olarak adlandırmak daha adil olacaktır. findMeşgul kutusu veya yadigarı-araç-çantası gibi bazı uygulamalar aynı sınırlamaya sahip olacaktır.
Stéphane Chazelas

3
Sen gerekiyordu -Liçin findsürüm eşdeğer olduğu -nt. Ayrıca ile başlayan dosya adlarını üzerinde başarısız olur -veya !, (...
Stéphane Chazelas

2
Nitekim, çatışmacı bir ifade kullandığımda sık sık aşağı oy alıyorum. Cevabın başlangıcında bağlamı (ikinci çözünürlüğe kesildiğinde aynı zaman damgası içinde değiştirilen dosyalar) belirtmeniz size yardımcı olacaktır.
Stéphane Chazelas

1
@schily, evet, BSD findsahip find -f "$file"olduğu için ancak taşınabilir değil.
Stéphane Chazelas
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.