जवाबों:
यह आसानी से 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
कमांड चलाकर आप पता लगा सकते हैं कि आप वर्तमान में किस लोकेल में हैं ।
यदि आप उपयोग कर रहे हैं तो आप zsh
कोष्ठक में ()
तथाकथित ग्लोब क्वालीफायर की सूची संलग्न कर सकते हैं जो वांछित फाइलों का चयन करते हैं। आपके मामले में, यह होगा
cp *(On[1,4]) ~/
यहाँ On
फ़ाइल नामों को वर्णानुक्रम में उल्टे क्रम में रखा गया है और [1,4]
उनमें से केवल 4 को ही लिया गया है।
आप केवल साधारण फाइलों के साथ (पाइप आदि निर्देशिका को छोड़कर,) का चयन करके इस और अधिक मजबूत कर सकते हैं .
, और यह भी जोड़कर --
को cp
इलाज फ़ाइलें जो नाम के साथ शुरू करने के क्रम में आदेश -
ठीक से, तो:
cp -- *(.On[1,4]) ~
D
यदि आप छिपी हुई फाइलों (डॉट-फाइल्स) पर विचार करना चाहते हैं तो क्वालीफायर जोड़ें :
cp -- *(D.On[1,4]) ~
*([-4,-1])
।
on
) में वर्णानुक्रम में छंटनी डिफ़ॉल्ट व्यवहार है, इसलिए इसे निर्दिष्ट करने की कोई आवश्यकता नहीं है, और -
संख्याओं के सामने नीचे से फ़ाइलनाम गिना जाता है।
यहां अत्यंत सरल बैश कमांड का उपयोग करके एक समाधान है।
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
कॉपी कमांड का प्रदर्शन करने वाली प्रत्येक पंक्ति पर लूप।
जब तक आपको शेल एग्रेसिव लगता है, तब तक आप कर सकते हैं:
set -- /path/to/source/dir/*
[ "$#" -le 4 ] || shift "$(($#-4))"
cp "$@" /path/to/target/dir
यह bash
पेशकश किए गए -specific सरणी समाधान के समान है , लेकिन किसी भी POSIX- संगत शेल के लिए पोर्टेबल होना चाहिए। दोनों विधियों के बारे में कुछ नोट:
यह महत्वपूर्ण है कि आप अपने cp
तर्कों का नेतृत्व करें w / cp --
या आप .
एक डॉट या /
प्रत्येक नाम के शीर्ष पर प्राप्त करें। यदि आप ऐसा करने में विफल रहते हैं, तो आप पहले तर्क -
में एक अग्रणी डैश का जोखिम उठाते हैं, cp
जिसे एक विकल्प के रूप में व्याख्या किया जा सकता है और ऑपरेशन विफल होने या अन्यथा अनपेक्षित परिणामों को प्रस्तुत करने का कारण बन सकता है।
set -- ./*
या array=(./*)
।यह सुनिश्चित करने के लिए दोनों तरीकों का उपयोग करते समय यह महत्वपूर्ण है कि आपके पास कम से कम आपके 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
सभी फाइलनामों में एक -स्टाइल प्रतिस्थापन को लागू करेगा क्योंकि यह उन्हें कॉपी करता है।
यदि केवल फाइलें हैं और उनके नाम में व्हॉट्सएप या न्यूलाइन (और आपने संशोधित नहीं किया है $IFS
) या ग्लोब कैरेक्टर (या कुछ गैर-प्रिंट करने योग्य वर्ण ls
), और कुछ के साथ शुरू नहीं होते हैं .
, तो आप ऐसा नहीं कर सकते :
cp -- $(ls | tail -n 4) ~/
a_
से सभी चार फ़ाइलों के लिए एक उपसर्ग prepend है ? मैंने कोशिश की echo "a_$(ls | tail -n 4)"
, लेकिन यह केवल पहली फ़ाइल को प्रस्तुत करता है।
ls
आउटपुट को खराब रूप माना जाता है क्योंकि यह आम तौर पर उन फ़ाइल नामों पर बुरी तरह से विफल होता है जिनमें न केवल रिक्त स्थान होते हैं, बल्कि टैब, न्यूलाइन या अन्य वैध लेकिन "मुश्किल" अक्षर भी होते हैं।
यह किसी भी लूप कोड के बिना एक सरल बैश समाधान है। वर्तमान dir से गंतव्य तक अंतिम 4 फ़ाइलों की प्रतिलिपि बनाएँ:
$ find . -maxdepth 1 -type f |tail -n -4|xargs cp -t "$destdir"
find
आपको वांछित क्रम में फाइलें मिलें? आप यह कैसे सुनिश्चित करते हैं कि उनके नाम में व्हॉट्सएप कैरेक्टर (नईलाइन सहित) फाइलें सही तरीके से हैंडल की गई हैं?
LC_ALL=C