लिनक्स 'फाइंड' के साथ केवल फ़ाइल नाम कैसे प्राप्त करें?


266

मैं निर्देशिका में सभी फ़ाइलों के लिए खोज का उपयोग कर रहा हूं, इसलिए मुझे रास्तों की एक सूची मिलती है। हालाँकि, मुझे केवल फ़ाइल नाम चाहिए। यानी मुझे मिलता है ./dir1/dir2/file.txtऔर मैं पाना चाहता हूंfile.txt

जवाबों:


359

GNU में findआप इसके लिए -printfपैरामीटर का उपयोग कर सकते हैं , जैसे:

find /dir1 -type f -printf "%f\n"

9
स्पष्ट रूप से उत्तर , लेकिन इसमें विस्तार का अभाव है।
जेसन मैकक्रेरी

25
यह केवल GNU के लिए है
ओसामा एफ एलियास

3
यह मेरे लिए काम नहीं करता है जब मैं कई फ़ाइल प्रकारों (-o स्विच) का उपयोग करता हूं
अर्चिन

9
खोज: -प्रिंट: अज्ञात प्राथमिक या ऑपरेटर
होम्स

@ उक्रिन कोई कारण नहीं है कि यह तब तक नहीं होना चाहिए जब तक कि आपके पास सही तर्क न हो (यानी -oनिहित की तुलना में कम पूर्ववर्तीता है -a, इसलिए आप अक्सर अपने -oतर्कों को समूह में रखना चाहेंगे )
मोनिका कृपया

157

यदि आपके खोज में -प्रिंट ऑप्शन नहीं है, तो आप बेसनेम का उपयोग भी कर सकते हैं:

find ./dir1 -type f -exec basename {} \;

17
अर्धविराम का हवाला देते हुए ... {} ';'
अवहेलना

28

उदाहरण के लिए, -execdirवर्तमान फ़ाइल को स्वचालित रूप से रखने का उपयोग करें {}:

find . -type f -execdir echo '{}' ';'

आप $PWDइसके बजाय उपयोग कर सकते हैं .(कुछ प्रणालियों पर यह सामने में एक अतिरिक्त डॉट का उत्पादन नहीं करेगा)।

यदि आपको अभी भी एक अतिरिक्त डॉट मिला है, तो वैकल्पिक रूप से आप चला सकते हैं:

find . -type f -execdir basename '{}' ';'

-execdir utility [argument ...] ;

-execdirप्राथमिक रूप से समान है -execअपवाद है कि उपयोगिता निर्देशिका कि से निष्पादित किया जाएगा के साथ प्राथमिक वर्तमान फ़ाइल रखती है

जब +इसके बजाय उपयोग किया जाता है ;, तो {}उपयोगिता के प्रत्येक आह्वान के लिए जितना संभव हो उतने पथनामों के साथ प्रतिस्थापित किया जाता है। दूसरे शब्दों में, यह सभी फ़ाइलनामों को एक पंक्ति में मुद्रित करेगा।


के ./filenameबदले मुझे मिल रहा है filename। आपकी आवश्यकताओं के आधार पर, यह ठीक हो सकता है या नहीं भी हो सकता है।
user276648

@ user276648 के $PWDबजाय के साथ प्रयास करें .
केनोरब ५'१

24

यदि आप GNU खोज का उपयोग कर रहे हैं

find . -type f -printf "%f\n"

या आप एक प्रोग्रामिंग भाषा का उपयोग कर सकते हैं जैसे रूबी (1.9+)

$ ruby -e 'Dir["**/*"].each{|x| puts File.basename(x)}'

यदि आप एक बैश (कम से कम 4) समाधान कल्पना करते हैं

shopt -s globstar
for file in **; do echo ${file##*/}; done

मैं आपके जवाब से प्रेरित था मदद करने के लिए sleske: serverfault.com/a/745968/329412
Nolwennig

11

यदि आप केवल फ़ाइल नाम के विरुद्ध कुछ कार्रवाई चलाना चाहते हैं, तो उपयोग basenameकरना कठिन हो सकता है।

उदाहरण के लिए यह:

find ~/clang+llvm-3.3/bin/ -type f -exec echo basename {} \; 

बस बेसन गूंज जाएगा /my/found/path। नहीं अगर हम फाइलनाम पर निष्पादित करना चाहते हैं तो हम क्या चाहते हैं।

लेकिन आप तब xargsआउटपुट कर सकते हैं । उदाहरण के लिए किसी अन्य dir में नामों के आधार पर फ़ाइलों को मारने के लिए:

cd dirIwantToRMin;
find ~/clang+llvm-3.3/bin/ -type f -exec basename {} \; | xargs rm

न गूंज -find ~/clang+llvm-3.3/bin/ -type f -exec basename {} \;
आम


1

-execऔर -execdirधीमे हैं, xargsराजा हैं।

$ alias f='time find /Applications -name "*.app" -type d -maxdepth 5'; \
f -exec basename {} \; | wc -l; \
f -execdir echo {} \; | wc -l; \
f -print0 | xargs -0 -n1 basename | wc -l; \
f -print0 | xargs -0 -n1 -P 8 basename | wc -l; \
f -print0 | xargs -0 basename | wc -l

     139
    0m01.17s real     0m00.20s user     0m00.93s system
     139
    0m01.16s real     0m00.20s user     0m00.92s system
     139
    0m01.05s real     0m00.17s user     0m00.85s system
     139
    0m00.93s real     0m00.17s user     0m00.85s system
     139
    0m00.88s real     0m00.12s user     0m00.75s system

xargsसमानता भी मदद करता है।

मजेदार रूप से पर्याप्त मैं xargsबिना के अंतिम मामले की व्याख्या नहीं कर सकता -n1। यह सही परिणाम देता है और यह सबसे तेज़ है¯\_(ツ)_/¯

( basenameकेवल 1 पथ तर्क लेता है, लेकिन xargsउन सभी को (वास्तव में 5000) बिना भेज देगा -n1। लिनक्स और ओपनबीडीएस, केवल ओओएसओएस पर काम नहीं करता है ...)

एक लिनक्स सिस्टम से कुछ बड़ी संख्याएँ यह देखने के लिए कि कैसे -execdirमदद करता है, लेकिन एक समानांतर की तुलना में अभी भी बहुत धीमा है xargs:

$ alias f='time find /usr/ -maxdepth 5 -type d'
$ f -exec basename {} \; | wc -l; \
f -execdir echo {} \; | wc -l; \
f -print0 | xargs -0 -n1 basename | wc -l; \
f -print0 | xargs -0 -n1 -P 8 basename | wc -l

2358
    3.63s real     0.10s user     0.41s system
2358
    1.53s real     0.05s user     0.31s system
2358
    1.30s real     0.03s user     0.21s system
2358
    0.41s real     0.03s user     0.25s system

1
सिर्फ एक और डेटा बिंदु: एक लंबे समय तक चलने में ओपनबेस पर findयह है -execdirकि नई प्रक्रियाएं बनाते हुए सबसे तेज़ हो जाता है एक अपेक्षाकृत महंगा ऑपरेशन है।
घटा

1

ईमानदारी से basenameऔर dirnameसमाधान आसान हैं, लेकिन आप इसे भी देख सकते हैं:

find . -type f | grep -oP "[^/]*$"

या

find . -type f | rev | cut -d '/' -f1 | rev

या

find . -type f | sed "s/.*\///"

0

जैसा कि दूसरों ने बताया है, आप संयोजन कर सकते हैं findऔर basename, लेकिन डिफ़ॉल्ट रूप से basenameकार्यक्रम केवल एक समय में एक पथ पर काम करेगा, इसलिए निष्पादन योग्य को प्रत्येक पथ ( find ... -execया तो का उपयोग करके find ... | xargs -n 1) के लिए एक बार लॉन्च करना होगा , जो संभवतः धीमा हो सकता है।

आप का उपयोग करते हैं -aपर विकल्प basenameहै, तो यह एक एकल मंगलाचरण में एक से अधिक फ़ाइल नाम, जिसका अर्थ है कि आप तो उपयोग कर सकते हैं स्वीकार कर सकते हैं xargsबिना -n 1समूह के लिए पथ एक साथ की आमंत्रण के एक दूर छोटी संख्या में, basenameहै, जो और अधिक कुशल होना चाहिए।

उदाहरण:

find /dir1 -type f -print0 | xargs -0 basename -a

यहां मैंने फ़ाइलों और निर्देशिकाओं के नाम के अंदर किसी भी व्हाट्सएप का सामना करने के लिए ( -print0और -0एक साथ इस्तेमाल किया जाना चाहिए) शामिल किया है।

यहाँ xargs basename -aऔर xargs -n1 basenameसंस्करणों के बीच एक समय की तुलना है । (एक समान-जैसी तुलना के लिए, यहां बताई गई टाइमिंग एक शुरुआती डमी रन के बाद की है, ताकि फाइल मेटाडाटा के पहले ही I / O कैश में कॉपी हो जाने के बाद वे दोनों हो जाएं।) मैंने आउटपुट को पाइप कर दिया है। cksumदोनों मामलों में, बस यह प्रदर्शित करने के लिए कि आउटपुट उपयोग की गई विधि से स्वतंत्र है।

$ time sh -c 'find /usr/lib -type f -print0 | xargs -0 basename -a | cksum'
2532163462 546663

real    0m0.063s
user    0m0.058s
sys 0m0.040s

$ time sh -c 'find /usr/lib -type f -print0 | xargs -0 -n 1 basename | cksum' 
2532163462 546663

real    0m14.504s
user    0m12.474s
sys 0m3.109s

जैसा कि आप देख सकते हैं, basenameहर बार लॉन्च करने से बचने के लिए यह वास्तव में काफी तेज है ।


@Minusf के उत्तर को अधिक अच्छी तरह से पढ़ते हुए, मैं देखता हूं कि मैक पर basenameकिसी भी अतिरिक्त कमांड लाइन तर्क की आवश्यकता के बिना कई फाइलनामों को स्वीकार किया जाएगा। -aयहाँ का उपयोग लिनक्स पर है। ( basename --versionमुझसे कहता है basename (GNU coreutils) 8.28।)
alaniwi

-3

मुझे एक समाधान मिला है (makandracards पेज पर), जो सिर्फ नया फ़ाइल नाम देता है:

ls -1tr * | tail -1

(धन्यवाद आर्ने हार्थरेज़ को जाता है)

मैंने इसके लिए इस्तेमाल किया cp:

cp $(ls -1tr * | tail -1) /tmp/

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