एक निर्देशिका में अंतिम एन फाइलें कैसे प्राप्त करें?


15

मेरे पास कई फाइलें हैं जो एक निर्देशिका में फ़ाइल नाम द्वारा आदेशित हैं। मैं अपने घर निर्देशिका में अंतिम एन (कहना, एन = 4) फ़ाइलों की प्रतिलिपि बनाना चाहता हूं। मैं इसे कैसे करूं?

cp ./<the final 4 files> ~/


1
नीचे दिए गए सभी उत्तरों पर, आपको श्रेणियों का उपयोग करके कमांड्स के सामने एक "LC_ALL = ..." जोड़ने की आवश्यकता हो सकती है, ताकि उनकी रेंज आपके लिए सही लोकेल का उपयोग करें (स्थान बदल सकते हैं, और वर्णों का क्रम तब बदल सकता है बहुत कुछ। पूर्व, कुछ स्थानों में, [az] में "Z" को छोड़कर वर्णमाला के सभी अक्षर हो सकते हैं, क्योंकि पत्रों का आदेश दिया गया है: aAbBcC .... zZ। अन्य विविधताएं मौजूद हैं (उच्चारण किए गए अक्षर, और यहां तक ​​कि अधिक आकर्षक विवरण। )। एक सामान्य विकल्प है:LC_ALL=C
ओलिवियर दुलक

जवाबों:


23

यह आसानी से bash / ksh93 / zsh सरणियों के साथ किया जा सकता है:

a=(*)
cp -- "${a[@]: -4}" ~/

यह सभी गैर-छिपे हुए फ़ाइल नामों के लिए भी काम करता है, भले ही उनमें रिक्त स्थान, टैब, न्यूलाइन्स या अन्य कठिन अक्षर हों (मान लें कि वर्तमान निर्देशिका में कम से कम 4 गैर-छिपी हुई फ़ाइलें हैं bash)।

यह काम किस प्रकार करता है

  • a=(*)

    यह aसभी फ़ाइल नामों के साथ एक सरणी बनाता है । बैश द्वारा लौटाए गए फ़ाइल नाम वर्णानुक्रम में क्रमबद्ध हैं। (मुझे लगता है कि यह आपका मतलब है "फ़ाइल नाम द्वारा आदेश दिया गया है।" )

  • ${a[@]: -4}

    यह सरणी के अंतिम चार तत्वों को aप्रदान करता है (बशर्ते सरणी में कम से कम 4 तत्व हों bash)।

  • cp -- "${a[@]: -4}" ~/

    यह अंतिम चार फ़ाइल नामों को आपके होम डायरेक्टरी में कॉपी करता है।

एक ही समय में कॉपी और नाम बदलने के लिए

यह अंतिम चार फाइलों को केवल होम डायरेक्टरी में कॉपी करेगा और उसी समय, a_कॉपी किए गए फाइल के नाम के लिए स्ट्रिंग को प्रीपेन्ड करेगा :

a=(*)
for fname in "${a[@]: -4}"; do cp -- "$fname" ~/a_"$fname"; done

एक अलग निर्देशिका से कॉपी करें और नाम बदलें

यदि हम a=(./some_dir/*)इसके बजाय का उपयोग करते हैं a=(*), तो हमारे पास निर्देशिका का मुद्दा फ़ाइल नाम से जुड़ा हुआ है। एक समाधान है:

a=(./some_dir/*) 
for f in "${a[@]: -4}"; do cp "$f"  ~/a_"${f##*/}"; done

एक अन्य समाधान एक उपधारा और उपधारा cdमें निर्देशिका का उपयोग करना है:

(cd ./some_dir && a=(*) && for f in "${a[@]: -4}"; do cp -- "$f" ~/a_"$f"; done) 

जब सबस्क्रिप्शन पूरा हो जाता है, तो शेल हमें मूल निर्देशिका में लौटाता है।

यह सुनिश्चित करना कि आदेश सुसंगत है

सवाल फाइल "फ़ाइल नाम द्वारा आदेश" के लिए पूछता है। वह आदेश, ओलिवियर दुलैक टिप्पणियों में बताते हैं, एक स्थान से दूसरे स्थान पर भिन्न होगा। यदि मशीन सेटिंग्स से स्वतंत्र परिणाम निर्धारित करना महत्वपूर्ण है, तो सरणी aपरिभाषित किए जाने पर स्थानीय रूप से स्पष्ट रूप से निर्दिष्ट करना सबसे अच्छा है। उदाहरण के लिए:

LC_ALL=C a=(*)

localeकमांड चलाकर आप पता लगा सकते हैं कि आप वर्तमान में किस लोकेल में हैं ।


9

यदि आप उपयोग कर रहे हैं तो आप zshकोष्ठक में ()तथाकथित ग्लोब क्वालीफायर की सूची संलग्न कर सकते हैं जो वांछित फाइलों का चयन करते हैं। आपके मामले में, यह होगा

cp *(On[1,4]) ~/

यहाँ Onफ़ाइल नामों को वर्णानुक्रम में उल्टे क्रम में रखा गया है और [1,4]उनमें से केवल 4 को ही लिया गया है।

आप केवल साधारण फाइलों के साथ (पाइप आदि निर्देशिका को छोड़कर,) का चयन करके इस और अधिक मजबूत कर सकते हैं ., और यह भी जोड़कर --को cpइलाज फ़ाइलें जो नाम के साथ शुरू करने के क्रम में आदेश -ठीक से, तो:

cp -- *(.On[1,4]) ~

Dयदि आप छिपी हुई फाइलों (डॉट-फाइल्स) पर विचार करना चाहते हैं तो क्वालीफायर जोड़ें :

cp -- *(D.On[1,4]) ~

2
या: *([-4,-1])
स्टीफन चेजलस

2
@ StéphaneChazelas हाँ, भविष्य के पाठकों के लिए स्पष्ट करने देता है कि सामान्य दिशा ( on) में वर्णानुक्रम में छंटनी डिफ़ॉल्ट व्यवहार है, इसलिए इसे निर्दिष्ट करने की कोई आवश्यकता नहीं है, और -संख्याओं के सामने नीचे से फ़ाइलनाम गिना जाता है।
jimmij

7

यहां अत्यंत सरल बैश कमांड का उपयोग करके एक समाधान है।

find . -maxdepth 1 -type f | sort | tail -n 4 | while read -r file; do cp "$file" ~/; done

स्पष्टीकरण:

find . -maxdepth 1 -type f

वर्तमान निर्देशिका में सभी फ़ाइलों को ढूँढता है।

sort

वर्णानुक्रम में कहते हैं।

tail -n 4

केवल अंतिम 4 लाइनें दिखाएं।

while read -r file; do cp "$file" ~/; done

कॉपी कमांड का प्रदर्शन करने वाली प्रत्येक पंक्ति पर लूप।


6

जब तक आपको शेल एग्रेसिव लगता है, तब तक आप कर सकते हैं:

set -- /path/to/source/dir/*
[ "$#" -le 4 ] || shift "$(($#-4))"
cp "$@" /path/to/target/dir

यह bashपेशकश किए गए -specific सरणी समाधान के समान है , लेकिन किसी भी POSIX- संगत शेल के लिए पोर्टेबल होना चाहिए। दोनों विधियों के बारे में कुछ नोट:

  1. यह महत्वपूर्ण है कि आप अपने cpतर्कों का नेतृत्व करें w / cp --या आप .एक डॉट या /प्रत्येक नाम के शीर्ष पर प्राप्त करें। यदि आप ऐसा करने में विफल रहते हैं, तो आप पहले तर्क -में एक अग्रणी डैश का जोखिम उठाते हैं, cpजिसे एक विकल्प के रूप में व्याख्या किया जा सकता है और ऑपरेशन विफल होने या अन्यथा अनपेक्षित परिणामों को प्रस्तुत करने का कारण बन सकता है।

    • भले ही वर्तमान निर्देशिका के साथ स्रोत निर्देशिका के रूप में काम कर रहा हो, यह आसानी से किया जाता है ... set -- ./*या array=(./*)
  2. यह सुनिश्चित करने के लिए दोनों तरीकों का उपयोग करते समय यह महत्वपूर्ण है कि आपके पास कम से कम आपके arg सरणी में कई आइटम हैं जैसा कि आप निकालने का प्रयास करते हैं - मैं यहां एक गणित विस्तार के साथ करता हूं। shiftकेवल तब होता है अगर कोई आर्ग सरणी में कम से कम 4 आइटम कर रहे हैं - और उसके बाद ही बदलाव दूर उन पहले आर्ग कि 4 का अधिशेष बनाना ..

    • तो एक set 1 2 3 4 5मामले में यह 1दूर स्थानांतरित हो जाएगा , लेकिन एक set 1 2 3मामले में, यह कुछ भी नहीं स्थानांतरित करेगा।
    • उदाहरण के लिए: a=(1 2 3); echo "${a[@]: -4}"एक रिक्त रेखा प्रिंट करता है।

यदि आप एक निर्देशिका से दूसरे में प्रतिलिपि बना रहे हैं, तो आप उपयोग कर सकते हैं pax:

set -- /path/to/source/dir/*
[ "$#" -le 4 ] || shift "$(($#-4))"
pax -rws '|.*/|new_prefix|' "$@" /path/to/target/dir

... जो sedसभी फाइलनामों में एक -स्टाइल प्रतिस्थापन को लागू करेगा क्योंकि यह उन्हें कॉपी करता है।


4

यदि केवल फाइलें हैं और उनके नाम में व्हॉट्सएप या न्यूलाइन (और आपने संशोधित नहीं किया है $IFS) या ग्लोब कैरेक्टर (या कुछ गैर-प्रिंट करने योग्य वर्ण ls), और कुछ के साथ शुरू नहीं होते हैं ., तो आप ऐसा नहीं कर सकते :

cp -- $(ls | tail -n 4) ~/

इसे कमांड प्रतिस्थापन कहा जाता है और यह वास्तव में आसान है। tldp.org/LDP/abs/html/commandsub.html#CSPARENS
iyrin

धन्यवाद! यह काम करता हैं। वहाँ जल्दी a_से सभी चार फ़ाइलों के लिए एक उपसर्ग prepend है ? मैंने कोशिश की echo "a_$(ls | tail -n 4)", लेकिन यह केवल पहली फ़ाइल को प्रस्तुत करता है।
सिब्ब्स जुआ

@ सिबेस गैंबिंग मेरा दृष्टिकोण इसके लिए उपयुक्त नहीं है, लेकिन जॉन 1024 का जवाब आसानी से उसी के अनुकूल हो सकता है।
हौके लैजिंग

5
सामान्य रूप से पार्सिंग lsआउटपुट को खराब रूप माना जाता है क्योंकि यह आम तौर पर उन फ़ाइल नामों पर बुरी तरह से विफल होता है जिनमें न केवल रिक्त स्थान होते हैं, बल्कि टैब, न्यूलाइन या अन्य वैध लेकिन "मुश्किल" अक्षर भी होते हैं।
HBruijn

2
@HaLLaging भले ही यह वर्तमान में कोई समस्या नहीं है (क्योंकि मेरी निर्देशिका में "जटिल" फ़िरनामेस नहीं हैं), मेरे पास 2 साल हो सकते हैं, और अचानक चीजें मेरे पैरों पर गिरती हैं ...
glglgl

1

यह किसी भी लूप कोड के बिना एक सरल बैश समाधान है। वर्तमान dir से गंतव्य तक अंतिम 4 फ़ाइलों की प्रतिलिपि बनाएँ:

$ find . -maxdepth 1 -type f |tail -n -4|xargs cp -t "$destdir"

1
आप यह कैसे सुनिश्चित करते हैं कि findआपको वांछित क्रम में फाइलें मिलें? आप यह कैसे सुनिश्चित करते हैं कि उनके नाम में व्हॉट्सएप कैरेक्टर (नईलाइन सहित) फाइलें सही तरीके से हैंडल की गई हैं?
Kusalananda
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.