POSIX श में प्रदर्शन -nt / -ot परीक्षण


11

बिल्ट-इन testऔर [यूटिलिटीज के पास -nt" -otगोले में" (" से अधिक नया") और ("पुराने से") परीक्षण होते हैं, तब भी जब शेल "पॉसिक्स मोड" में चल रहा होता है (समान नामों की बाहरी उपयोगिताओं के लिए भी सही है। वे प्रणालियाँ जिनकी मुझे एक्सेस है)। ये परीक्षण दो फाइलों पर संशोधन टाइमस्टैम्प की तुलना करने के लिए हैं। उनके प्रलेखित शब्दार्थ पूरे कार्यान्वयन में थोड़े भिन्न होते हैं (यदि एक या दूसरी फ़ाइल मौजूद नहीं है तो क्या होता है) के संबंध में, लेकिन वे POSIX कल्पनाtest में शामिल नहीं हैं के लिए उपयोगिता

testजब सशर्त आदेश [KornShell] शेल से हटा दिया गया था, तो उन्हें उपयोगिता में आगे नहीं ले जाया गया क्योंकि उन्हें testउपयोगिता के ऐतिहासिक कार्यान्वयन में निर्मित उपयोगिता में शामिल नहीं किया गया है sh

मान लें कि मैं एक /bin/shशेल स्क्रिप्ट में फ़ाइलों के बीच संशोधन टाइमस्टैम्प की तुलना करना चाहता हूं और फिर इस पर निर्भर करता है कि क्या एक फ़ाइल दूसरे की तुलना में नई है, जैसे कि

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

... इसके अलावा मैं और कौन सी उपयोगिता का उपयोग कर सकता था make(जो बाकी स्क्रिप्ट को कम से कम कहने के लिए अनिच्छुक बना देगा)? या मुझे बस यह मान लेना चाहिए कि कोई भी कभी भी "ऐतिहासिक कार्यान्वयन" पर स्क्रिप्ट को चलाने वाला नहीं है sh, या एक विशिष्ट शेल जैसे लेखन के लिए इस्तीफा दे सकता है bash?


जैसा कि आप मेरे जवाब में देख सकते हैं, बैश एक तरह से -ntफीचर को लागू नहीं करता है testजो लगभग अनुमानित है। 1995. आपको सही व्यवहार पसंद होने पर findभी bashआपको बेस अभिव्यक्ति का उपयोग करना चाहिए ।
शास्त्री

जवाबों:


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

फ़ाइलों के साथ एक गलत सकारात्मक को रोकने के लिए फ़ाइलों को पूर्ण पथ का उपयोग करना newlines ही शामिल है।

रिश्तेदार पथ का उपयोग करने के मामले में, फिर findकमांड को इसमें बदलें :

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

तकनीकी रूप से, मुझे लगता है कि यह विफल होता है यदि $f1केवल नई
रूपरेखाएँ

1
@ilkachach के साथ -exec echo x \;या इसी तरह के आसपास काम किया जा सकता है ?
मुरु

@ मुरु, हाँ। -printfअगर यह मानक होता तो आसान होता
ilkachachu

3
@ कुसलानंद AFAICT, findके बाहर निकलने की स्थिति स्वतंत्र है जो कि findवापसी के अलग-अलग परीक्षण - शायद सिवाय इसके कि वास्तव में उन परीक्षणों को चलाने में कोई त्रुटि है। find0 से बाहर निकलता है, भले ही कोई फाइल न मिले।
मुरु

1
ध्यान दें कि [ / -nt /nofile ]कार्यान्वयन के साथ व्यवहार भिन्न होता है (लेकिन कभी कोई त्रुटि उत्पन्न नहीं करता है)।
स्टीफन चेजालस

7

यह सबसे पुराने यूनिक्स कमांड में से एक का उपयोग करने के लिए एक मामला हो सकता है ls

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

परिणाम सही है अगर a, b से नया है।


3
यदि फ़ाइल के नाम -(गायब --) से शुरू होते हैं तो यह काम नहीं करता है । आपको -Lइसके समतुल्य होने की आवश्यकता होगी -nt। यह तुलना xऔर $'x\nx'उदाहरण के लिए काम नहीं करता है ।
स्टीफन चेजलस

1
EEK! लेकिन यह भी।
Kusalananda

4

आपने एक दिलचस्प सवाल उठाया और दावा किया कि पहले सत्यापित किया जाना चाहिए।

मैंने के व्यवहार की जाँच की:

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

विभिन्न गोले के साथ। यहाँ परिणाम हैं:

  • मार काम नहीं करता है - कुछ भी नहीं छापता है।

  • बोश काम करता है

  • पानी का छींटा काम नहीं करता है - कुछ भी नहीं छापता है।

  • ksh88 काम नहीं करता है - कुछ भी नहीं छापता है।

  • ksh93 काम करता है

  • mksh काम नहीं करता है - कुछ भी नहीं छापता है।

  • पॉश प्रिंट: पॉश: [: -न: अप्रत्याशित ऑपरेटर / ऑपरेंड

  • यश काम करता है

  • zsh नए संस्करणों में काम करता है , पुराने संस्करण कुछ नहीं छापते हैं

तो चार में से नौ गोले -फीचर का समर्थन करते हैं और इसे सही तरीके से लागू करते हैं। इस मामले में सही अर्थ है: हाल के प्लेटफार्मों पर समय टिकटों की तुलना करने में सक्षम है जो उप-सेकंड टाइम स्टांप ग्रैन्युलैरिटी का समर्थन करते हैं । ध्यान दें कि मेरे द्वारा चुनी गई फाइलें आमतौर पर उनके समय टिकटों में केवल कुछ माइक्रोसेकंड से भिन्न होती हैं।

चूंकि एक कार्यशील findकार्यान्वयन को खोजना आसान है , इसलिए मैं प्रतिस्थापित करने की सलाह देता हूं

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

एक findआधारित अभिव्यक्ति द्वारा ।

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

कम से कम तब तक काम करता है, जब तक कि $file1इसमें केवल नई-नई लाइनें न हों।

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

थोड़ा धीमा है लेकिन सही तरीके से काम करता है।

बीटीडब्ल्यू: मेक मी के बारे में मैं सभी मेक अप लागू करने के लिए नहीं बोल सकता, लेकिन SunPro Makeलगभग उसी समय से नैनोसेकंड ग्रैन्युलैरिटी के साथ तुलना का समर्थन करता है। 20 साल है, जबकि smakeऔर gmakeहाल ही में इस सुविधा को जोड़ा।


1
क्या "काम नहीं कर रहे" परीक्षण सब-सेकंड टाइमस्टैम्प (निश्चित रूप से?), या कुछ और की तुलना करने में विफलता के कारण काम नहीं कर रहे हैं? आपके परीक्षण में शामिल फाइलों पर वास्तविक टाइमस्टैम्प क्या है? परीक्षण के लिए +1!
Kusalananda

2
मुझे लगता है कि गिरावट संभवतः टकराव के शब्दों के बारे में है। यहां, इसे सीमा (कुछ संदर्भों में महत्वपूर्ण) कहा जाना उचित होगा। findबिजीबॉक्स या हिरलूम-टूलचस्ट जैसे कुछ कार्यान्वयन में समान सीमा होगी।
स्टीफन चेजलस

3
आपको संस्करण के समकक्ष होने -Lकी आवश्यकता होगी । यह भी फ़ाइल नाम है कि के साथ शुरू पर विफल हो जाएगा या , ...find-nt-!(
स्टीफन Chazelas

2
तथ्य की बात के रूप में, मैं अक्सर टकराव हो जाता है जब मैं एक टकराव के शब्दों का उपयोग करता हूं। यदि आपने संदर्भ (उसी संकल्प के भीतर संशोधित की गई फ़ाइलें, जब दूसरे रिज़ॉल्यूशन में छोटा किया जाता है) को उत्तर की शुरुआत में मदद मिलेगी।
स्टीफन चेजेलस

1
@ सामान्य रूप से, हां, बीएसडी findइसके find -f "$file"लिए है, लेकिन यह पोर्टेबल नहीं है।
स्टीफन चेजालस
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.