बैश फ़ंक्शन नवीनतम फ़ाइल मिलान पैटर्न खोजने के लिए


141

बैश में, मैं एक फ़ंक्शन बनाना चाहता हूं जो एक निश्चित पैटर्न से मेल खाने वाली नवीनतम फ़ाइल का फ़ाइल नाम लौटाता है। उदाहरण के लिए, मेरे पास फ़ाइलों की एक निर्देशिका है:

Directory/
   a1.1_5_1
   a1.2_1_4
   b2.1_0
   b2.2_3_4
   b2.3_2_0

मुझे सबसे नई फ़ाइल चाहिए जो 'b2' से शुरू होती है। मैं इसे बाश में कैसे करूं? मुझे अपनी ~/.bash_profileस्क्रिप्ट में ऐसा करने की आवश्यकता है ।


4
अधिक उत्तर के संकेत के लिए superuser.com/questions/294161/… देखें । सॉर्टिंग आपकी नई फ़ाइल पाने के लिए महत्वपूर्ण कदम है
वोल्फगैंग फ़ाहल

जवाबों:


229

lsआदेश एक पैरामीटर है -tसमय से सॉर्ट करने के। फिर आप पहले (सबसे नए) को पकड़ सकते हैं head -1

ls -t b2* | head -1

लेकिन सावधान रहें: आपको ls के आउटपुट को पार्स क्यों नहीं करना चाहिए

मेरी व्यक्तिगत राय: पार्सिंग lsकेवल तभी खतरनाक है जब फ़ाइलनाम में रिक्त स्थान या नई रेखाओं जैसे मजाकिया चरित्र हो सकते हैं। यदि आप गारंटी दे सकते हैं कि फ़ाइल नाम में मजाकिया पात्र नहीं होंगे तो पार्सिंग lsकाफी सुरक्षित है।

यदि आप एक ऐसी स्क्रिप्ट विकसित कर रहे हैं, जो कई लोगों द्वारा कई अलग-अलग स्थितियों में कई प्रणालियों द्वारा चलाए जाने के लिए है, तो मैं बहुत कुछ नहीं करने की सलाह देता हूं ls

यह है कि यह "सही" कैसे किया जाए : मैं एक निर्देशिका में नवीनतम (सबसे नया, सबसे पुराना, सबसे पुराना) फ़ाइल कैसे पा सकता हूं?

unset -v latest
for file in "$dir"/*; do
  [[ $file -nt $latest ]] && latest=$file
done

8
दूसरों पर ध्यान दें: यदि आप ऐसा किसी निर्देशिका के लिए कर रहे हैं, तो आप -s विकल्प को ls में जोड़ देंगे, जैसे यह 'ls -td <पैटर्न> | सिर -1 '
ken.ganong 19

5
पार्स लोकसभा लिंक यह करने के लिए नहीं कहते हैं और में तरीकों की सिफारिश की BashFAQ 99 । मैं एक स्क्रिप्ट में शामिल करने के लिए बुलेट-प्रूफ के बजाय 1-लाइनर की तलाश कर रहा हूं, इसलिए मैं @manmana की तरह बेवजह ls पार्स करता रहूंगा।
०१ पर ०२:५४

1
@ नाम: यदि आप नाजुक का उपयोग किए बिना एक लाइनर की तलाश कर रहे हैं ls, printf "%s\n" b2* | head -1तो यह आपके लिए करेगा।
डेविड ओंगारो

2
@DavidOngaro सवाल यह नहीं कहता है कि फ़ाइल नाम संस्करण संख्याएँ हैं। यह संशोधन के समय के बारे में है। फ़ाइल नाम धारणा के साथ भी b2.10_5_2इस समाधान को मारता है।
अनामिका

1
आपका एक लाइनर मुझे सही उत्तर दे रहा है, लेकिन "सही" तरीका वास्तव में मुझे सबसे पुरानी फाइल दे रहा है । कोई विचार क्यों?
न्यूनेमस्टैट

15

के संयोजन findऔर के lsलिए अच्छी तरह से काम करता है

  • नई कहानियों के बिना फ़ाइल नाम
  • फ़ाइलों की बहुत बड़ी मात्रा में नहीं
  • बहुत लंबे फ़ाइलनाम नहीं

समाधान:

find . -name "my-pattern" -print0 |
    xargs -r -0 ls -1 -t |
    head -1

चलो इसे तोड़ दो:

साथ findहम इस तरह सभी दिलचस्प फ़ाइलों से मेल कर सकते हैं:

find . -name "my-pattern" ...

तब -print0हम lsइस तरह से सभी फ़ाइलनामों को सुरक्षित रूप से पास कर सकते हैं :

find . -name "my-pattern" -print0 | xargs -r -0 ls -1 -t

अतिरिक्त findखोज पैरामीटर और पैटर्न यहां जोड़े जा सकते हैं

find . -name "my-pattern" ... -print0 | xargs -r -0 ls -1 -t

ls -tसंशोधन समय (पहले नया) द्वारा फ़ाइलों को सॉर्ट करेगा और इसे एक पंक्ति में प्रिंट करेगा। आप -cसृजन समय के अनुसार क्रमबद्ध करने के लिए उपयोग कर सकते हैं । नोट : यह नए नाम वाले फ़ाइल नाम के साथ टूट जाएगा।

अंत में head -1हमें सॉर्ट की गई सूची में पहली फ़ाइल मिलती है।

नोट: xargs तर्क सूची के आकार के लिए सिस्टम सीमा का उपयोग करें। यदि यह आकार अधिक हो जाता है, xargsतो lsकई बार कॉल करेगा । यह छंटाई को तोड़ देगा और शायद अंतिम आउटपुट भी। Daud

xargs  --show-limits

आप सिस्टम पर सीमा की जांच करने के लिए।

नोट 2:find . -maxdepth 1 -name "my-pattern" -print0 यदि आप सबफ़ोल्डर्स के माध्यम से फ़ाइलों को खोजना नहीं चाहते हैं तो उपयोग करें।

नोट 3: जैसा कि @starfry द्वारा बताया गया है - के लिए -rतर्क xargsरोक रहा है ls -1 -t, अगर कोई फाइल मेल नहीं खाती थी find। शुगर के लिए धन्यवाद।


2
यह ls आधारित समाधानों से बेहतर है, क्योंकि यह निर्देशिकाओं के लिए बहुत अधिक फ़ाइलों के साथ काम करता है, जहाँ ls chokes हैं।
Marcin Zukowski

find . -name "my-pattern" ... -print0मुझे देता हैfind: paths must precede expression: `...'
Jaakko

ओह! ..."अधिक मापदंडों" के लिए खड़ा है। यदि आपको इसकी आवश्यकता नहीं है, तो बस इसे छोड़ दें।
बोरिस ब्रैडस्की

2
मैंने पाया कि यह एक ऐसी फाइल को लौटा सकता है जो पैटर्न से मेल नहीं खाती है अगर पैटर्न से मेल नहीं खाती है। ऐसा इसलिए होता है क्योंकि खोज कुछ भी नहीं xargs को पास करता है, जो तब बिना किसी फ़ाइल सूची के ls को आमंत्रित करता है, जिससे यह सभी फाइलों पर काम करता है। समाधान -rxargs कमांड-लाइन में जोड़ने के लिए है जो xargs को इसकी कमांड-लाइन नहीं चलाने के लिए कहता है अगर उसे अपने मानक इनपुट पर कुछ भी नहीं मिलता है।
स्टार

@starfry धन्यवाद! अच्छा पकड़ा। मैंने -rजवाब में जोड़ा ।
बोरिस ब्रोडस्की

7

यह आवश्यक बैश फ़ंक्शन का एक संभावित कार्यान्वयन है:

# Print the newest file, if any, matching the given pattern
# Example usage:
#   newest_matching_file 'b2*'
# WARNING: Files whose names begin with a dot will not be checked
function newest_matching_file
{
    # Use ${1-} instead of $1 in case 'nounset' is set
    local -r glob_pattern=${1-}

    if (( $# != 1 )) ; then
        echo 'usage: newest_matching_file GLOB_PATTERN' >&2
        return 1
    fi

    # To avoid printing garbage if no files match the pattern, set
    # 'nullglob' if necessary
    local -i need_to_unset_nullglob=0
    if [[ ":$BASHOPTS:" != *:nullglob:* ]] ; then
        shopt -s nullglob
        need_to_unset_nullglob=1
    fi

    newest_file=
    for file in $glob_pattern ; do
        [[ -z $newest_file || $file -nt $newest_file ]] \
            && newest_file=$file
    done

    # To avoid unexpected behaviour elsewhere, unset nullglob if it was
    # set by this function
    (( need_to_unset_nullglob )) && shopt -u nullglob

    # Use printf instead of echo in case the file name begins with '-'
    [[ -n $newest_file ]] && printf '%s\n' "$newest_file"

    return 0
}

यह केवल बैश बिल्डिंस का उपयोग करता है, और उन फ़ाइलों को संभालना चाहिए जिनके नाम में नईलाइन या अन्य असामान्य अक्षर हैं।


1
आप उपयोग कर सकते हैं nullglob_shopt=$(shopt -p nullglob)और फिर बाद $nullglobमें इसे वापस रख सकते हैं nullglobकि यह पहले कैसे था।
gniourf_gniourf

$ (Shopt -p nullglob) का उपयोग करने के लिए @gniourf_gniourf द्वारा सुझाव एक अच्छा है। मैं आमतौर पर कमांड प्रतिस्थापन ( $()या बैकटिक्स) का उपयोग करने से बचने की कोशिश करता हूं क्योंकि यह धीमा है, विशेष रूप से सिग्विन के तहत, यहां तक ​​कि जब कमांड केवल बिल्डिन का उपयोग करता है। इसके अलावा, उप-संदर्भ, जिसमें आदेश मिलते हैं, कभी-कभी उन्हें अप्रत्याशित तरीके से व्यवहार करने का कारण बन सकते हैं। मैं चर (जैसे nullglob_shopt) में स्टोरिंग कमांड से बचने की कोशिश करता हूं क्योंकि बहुत खराब चीजें हो सकती हैं यदि आपको चर का मान गलत मिलता है।
पीपीएच

मैं उन विवरणों की ओर ध्यान आकर्षित करता हूं, जिनकी अनदेखी करने पर अस्पष्ट विफलता हो सकती है। धन्यवाद!
रॉन बुर्क

मुझे लगता है कि आप समस्या को हल करने के लिए और अधिक अनोखे तरीके से गए थे! यह निश्चित है कि यूनिक्स / लिनक्स में 'स्किन cat!' के लिए एक से अधिक तरीके हैं । यहां तक ​​कि अगर यह अधिक काम लेता है, तो लोगों को अवधारणाओं को दिखाने का लाभ होता है। एक +1 है!
प्रीफटन

3

असामान्य फ़ाइल नाम (जैसे कि मान्य \nवर्ण वाली फ़ाइल इस तरह के पार्सिंग के साथ कहर बरपा सकती है। यहां पर्ल में इसे करने का एक तरीका है:

perl -le '@sorted = map {$_->[0]} 
                    sort {$a->[1] <=> $b->[1]} 
                    map {[$_, -M $_]} 
                    @ARGV;
          print $sorted[0]
' b2*

यह एक श्वार्टजियन ट्रांसफ़ॉर्मेशन है जिसका इस्तेमाल वहाँ किया जाता है।


1
हो सकता है कि schwartz आपके साथ हो!
नाथन मोंटलीन

यह जवाब काम कर सकता है, लेकिन मुझे विश्वास नहीं होगा कि यह खराब प्रलेखन को देखते हुए।
वोल्फगैंग फाहल

1

आप statफ़ाइल ग्लोब के साथ उपयोग कर सकते हैं और सामने की तरफ जोड़े गए फ़ाइल समय के साथ एक सजावट-प्रकार-अघोषित:

$ stat -f "%m%t%N" b2* | sort -rn | head -1 | cut -f2-

नहीं। "स्टेट: '% m% t% N' के लिए फ़ाइल सिस्टम जानकारी नहीं पढ़ सकता: ऐसी कोई फ़ाइल या निर्देशिका नहीं"
केन इनग्राम

मुझे लगता है कि यह मैक / फ्रीबीएसडी संस्करण के लिए हो सकता है stat, अगर मैं इसके विकल्पों को सही ढंग से याद कर रहा हूं। अन्य प्लेटफार्मों पर समान आउटपुट प्राप्त करने के लिए, आप उपयोग कर सकते हैंstat -c $'%Y\t%n' b2* | sort -rn | head -n1 | cut -f2-
जेफरी कैश

1

जो लोग find ... xargs ... head ...ऊपर समाधान चाहते हैं, उनके लिए डार्क मैजिक फंक्शन इनकैंटेशन , लेकिन फंक्शन फॉर्म का उपयोग करना आसान है, इसलिए आपको यह सोचने की जरूरत नहीं है:

#define the function
find_newest_file_matching_pattern_under_directory(){
    echo $(find $1 -name $2 -print0 | xargs -0 ls -1 -t | head -1)
}

#setup:
#mkdir /tmp/files_to_move
#cd /tmp/files_to_move
#touch file1.txt
#touch file2.txt

#invoke the function:
newest_file=$( find_newest_file_matching_pattern_under_directory /tmp/files_to_move/ bc* )
echo $newest_file

प्रिंटों:

file2.txt

जो है:

दिए गए निर्देशिका से मेल खाते के तहत फ़ाइल के सबसे पुराने संशोधित टाइमस्टैम्प के साथ फ़ाइल नाम दिया गया है।


1

खोज आदेश का उपयोग करें।

मान लें कि आप बैश 4.2+ का उपयोग कर रहे हैं, -printf '%T+ %p\n'फ़ाइल टाइमस्टैम्प मान के लिए उपयोग करें ।

find $DIR -type f -printf '%T+ %p\n' | sort -r | head -n 1 | cut -d' ' -f2

उदाहरण:

find ~/Downloads -type f -printf '%T+ %p\n' | sort -r | head -n 1 | cut -d' ' -f2

अधिक उपयोगी स्क्रिप्ट के लिए, यहां नवीनतम-नवीनतम स्क्रिप्ट देखें : https://github.com/l3x/helpers


उन फ़ाइल नामों के साथ काम करने के लिए जिनमें रिक्त स्थान में कटौती -d '' -f2,3,4,5,6,7,8,9,9 ...
Valodzka

0

इसे प्राप्त करने का एक अधिक कुशल तरीका है। निम्नलिखित आदेश पर विचार करें:

find . -cmin 1 -name "b2*"

यह कमांड "b2 *" पर वाइल्डकार्ड खोज के साथ एक मिनट पहले निर्मित नवीनतम फ़ाइल को ढूंढता है। यदि आप पिछले दो दिनों से फाइलें चाहते हैं तो आप नीचे दिए गए आदेश का उपयोग करके बेहतर होंगे:

find . -mtime 2 -name "b2*"

""। वर्तमान निर्देशिका का प्रतिनिधित्व करता है। उम्मीद है की यह मदद करेगा।


9
यह वास्तव में "नवीनतम फ़ाइल मिलान पैटर्न" नहीं पाता है ... यह सिर्फ एक मिनट पहले बनाई गई सभी फाइलों को मिलाता है, या दो दिन पहले संशोधित किया गया है।
GnP

यह उत्तर प्रशस्त प्रश्न पर आधारित था। इसके अलावा, आप नवीनतम फ़ाइल को देखने के लिए एक दिन या उससे पहले आने वाली कमांड को देख सकते हैं। यह इस बात पर निर्भर करता है कि आप क्या करने की कोशिश कर रहे हैं।
Naufal

"ट्वीकिंग" इसका जवाब नहीं है। यह एक उत्तर के रूप में इसे पोस्ट करने जैसा है: "बस खोज कमांड को घुमाएं और जो आप करना चाहते हैं उसके आधार पर उत्तर ढूंढें"।
केनेट सेलेस्टे

अनावश्यक टिप्पणी के बारे में निश्चित नहीं है। यदि आपको ऐसा लगता है कि मेरा उत्तर निश्चित नहीं है, तो कृपया उचित कारण बताएं कि मेरा उत्तर परीक्षा से कोई मतलब नहीं है। यदि ऐसा करने में असमर्थ हैं, तो कृपया आगे टिप्पणी करने से बचें।
नौफाल

1
आपके समाधान के लिए आपको यह जानना होगा कि नवीनतम फ़ाइल कब बनाई गई थी। यह प्रश्न में नहीं था इसलिए नहीं, आपका उत्तर प्रश्न के आधार पर नहीं है।
पब
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.