मैं पाश के लिए कैसे रिवर्स कर सकता हूं?


26

मैं ठीक सेfor रिवर्स ऑर्डर में एक लूप कैसे कर सकता हूं ?

for f in /var/logs/foo*.log; do
    bar "$f"
done

मुझे एक समाधान की आवश्यकता है जो फ़ाइल नामों में फंकी पात्रों के लिए नहीं टूटता है।


5
बस से sort -rपहले पाइप for, या के माध्यम से launder ls -r
डेविड श्वार्ट्ज

जवाबों:


27

बैश या ksh में, फ़ाइल नामों को किसी सरणी में रखें, और उस सरणी पर उल्टे क्रम में पुनरावृति करें।

files=(/var/logs/foo*.log)
for ((i=${#files[@]}-1; i>=0; i--)); do
  bar "${files[$i]}"
done

यदि ksh_arraysविकल्प सेट है (तो यह ksh इम्यूलेशन मोड में है) ऊपर का कोड भी zsh में काम करता है । Zsh में एक सरल विधि है, जो ग्लोब क्वालीफायर के माध्यम से मैचों के क्रम को उल्टा करने के लिए है:

for f in /var/logs/foo*.log(On); do bar $f; done

POSIX में सरणियाँ शामिल नहीं हैं, इसलिए यदि आप पोर्टेबल होना चाहते हैं, तो स्ट्रिंग्स की एक सरणी को सीधे स्टोर करने का आपका एकमात्र विकल्प स्थितिगत पैरामीटर है।

set -- /var/logs/foo*.log
i=$#
while [ $i -gt 0 ]; do
  eval "f=\${$i}"
  bar "$f"
  i=$((i-1))
done

एक बार जब आप स्थितीय मापदंडों का उपयोग कर रहे हैं, तो आपके चर की कोई आवश्यकता नहीं है iऔर f; बस shift, $1अपने कॉल के लिए उपयोग करें bar, और [ -z $1 ]अपने में परीक्षण करें while
user1404316

@ user1404316 यह आरोही क्रम में तत्वों पर पुनरावृत्ति का एक जटिल तरीका होगा । इसके अलावा, गलत: न तो [ -z $1 ]और न ही [ -z "$1" ]उपयोगी परीक्षण हैं (क्या होगा अगर पैरामीटर था *, या एक खाली स्ट्रिंग?)। और किसी भी मामले में वे यहां मदद नहीं करते हैं: सवाल यह है कि विपरीत क्रम में लूप कैसे किया जाए।
गिल्स एसओ- बुराई को रोकना '

यह प्रश्न विशेष रूप से कहता है कि यह फ़ाइल नामों पर / var / log में पुनरावृत्ति कर रहा है, इसलिए यह मान लेना सुरक्षित है कि कोई भी पैरामीटर "*" या रिक्त नहीं होगा। मैं रिवर्स ऑर्डर के बिंदु पर, हालांकि, सही खड़ा हूं।
user1404316

7

जब तक आप पंक्ति को "कायरता वर्ण" नहीं मानते, तब तक यह कोशिश करें:

ls /var/logs/foo*.log | tac | while read f; do
    bar "$f"
done

क्या कोई विधि है जो लाइन ब्रेक के साथ काम करती है? (मुझे पता है कि यह दुर्लभ है, लेकिन कम से कम सीखने के लिए मैं यह जानना चाहता हूं कि क्या सही कोड लिखना संभव है।)
मेहरदाद

प्रवाह को उलटने के लिए टैक का उपयोग करने के लिए रचनात्मक, और यदि आप कुछ अनचाहे पात्रों से छुटकारा पाना पसंद करते हैं जैसे कि लाइन ब्रेक आप tr -d '\ n' पर पाइप कर सकते हैं।
जोहान

4
यह टूट जाता है अगर फ़ाइल के नाम में newlines, backslashes या unprintable अक्षर होते हैं। Mywiki.wooledge.org/ParsingLs और फ़ाइल की तर्ज पर लूप कैसे देखें ? (और लिंक किए गए धागे)।
गिल्स एसओ- बुराई को रोकना '

सबसे अधिक मत वाले उत्तर ने fमेरी स्थिति में परिवर्तनशीलता को तोड़ दिया । यह उत्तर हालांकि, साधारण forलाइन के लिए ड्रॉप-इन प्रतिस्थापन के रूप में बहुत अधिक कार्य करता है ।
सर्ज स्ट्रोबोबांट

2

यदि कोई यह पता लगाने की कोशिश कर रहा है कि अंतरिक्ष-सीमांकित स्ट्रिंग सूची पर पुनरावृति कैसे करें, तो यह काम करता है:

reverse() {
  tac <(echo "$@" | tr ' ' '\n') | tr '\n' ' '
}

list="a bb ccc"

for i in `reverse $list`; do
  echo "$i"
done
> ccc
> bb 
> a

2
मेरे पास अपने सिस्टम पर tac नहीं है; मुझे नहीं पता कि यह मजबूत है, लेकिन मैं $ {mylist} में x का उपयोग कर रहा हूं; do revv = "$ {x} $ {revv}"; किया
arp

@ आरएपी GNU कोरुटिल्स का tacएक हिस्सा है। लेकिन आपका समाधान भी एक अच्छा है।
ACK_stoverflow

@ACK_stoverflow लिनक्स यूजरलैंड टूल के बिना सिस्टम हैं।
Kusalananda

@ कुसलानंद क्या आप कह रहे हैं कि केवल लिनक्स ही जीएनयू कोर्यूटिल्स का उपयोग करता है? जबरदस्त हंसी। यहां तक ​​कि बिजीबॉक्स भी है tac। हालांकि tacयहाँ पर बिना-प्रतिक्रिया के संख्या से मुझे लगता है कि शायद OSX tac नहीं है। जिस स्थिति में @ arp के समाधान के कुछ प्रकार का उपयोग करें - वैसे भी समझना आसान है।
ACK_stoverflow

@ACK_stoverflow मैं यही कह रहा हूँ, हाँ।
Kusalananda

1
find /var/logs/ -name 'foo*.log' -print0 | tail -r | xargs -0 bar

आपके इच्छित तरीके को संचालित करना चाहिए (यह मैक ओएस एक्स पर परीक्षण किया गया था और मेरे पास नीचे एक चेतावनी है ...)।

खोजने के लिए आदमी पृष्ठ से:

-print0
         This primary always evaluates to true.  It prints the pathname of the current file to standard output, followed by an ASCII NUL character (charac-
         ter code 0).

असल में, आप उन फ़ाइलों को ढूंढ रहे हैं जो आपके स्ट्रिंग + ग्लोब से मेल खाती हैं और प्रत्येक को NUL वर्ण से समाप्त करती हैं। यदि आपके फ़ाइल नाम में नई लाइनें या अन्य अजीब अक्षर हैं, तो आपको इसे अच्छी तरह से संभालना चाहिए।

tail -r

पाइप के माध्यम से मानक इनपुट लेता है और इसे उलट देता है (ध्यान दें कि सभी इनपुट को स्टडआउट में tail -rप्रिंट करता है, और न केवल अंतिम 10 लाइनें, जो मानक डिफ़ॉल्ट है। man tailअधिक जानकारी के लिए)।

हम फिर उसे पाइप करते हैं xargs -0:

-0      Change xargs to expect NUL (``\0'') characters as separators, instead of spaces and newlines.  This is expected to be used in concert with the
         -print0 function in find(1).

यहाँ, xargs को NUL चरित्र द्वारा अलग किए गए तर्कों को देखने की उम्मीद है, जिन्हें आपने पास किया findऔर उलट दिया tail

मेरी चेतावनी: मैंने पढ़ा है कि tailअशक्त-समाप्त स्ट्रिंग्स के साथ अच्छा नहीं खेलता । मैक ओएस एक्स पर यह अच्छी तरह से काम करता है, लेकिन मैं गारंटी नहीं दे सकता कि सभी * निक्स के मामले में। सावधानी से चलना।

मुझे यह भी उल्लेख करना चाहिए कि GNU समानांतर का उपयोग अक्सर एक xargsविकल्प के रूप में किया जाता है । आप यह भी देख सकते हैं।

मुझे कुछ याद आ रहा है, इसलिए दूसरों को झंकारना चाहिए।


2
+1 शानदार जवाब। ऐसा लगता है कि उबंटू tail -rहालांकि समर्थन नहीं करता है ... क्या मैं कुछ गलत कर रहा हूं?
मेहरदाद

1
नहीं, मुझे नहीं लगता कि आप हैं। मेरे पास अपनी linux मशीन नहीं है, लेकिन 'linux tail man' के लिए एक त्वरित Google इसे एक विकल्प के रूप में नहीं दिखाता है। सुनकु ने tacएक विकल्प के रूप में उल्लेख किया है , इसलिए मैं इसके बजाय कोशिश
करूंगा

मैंने
tcdyl

जब मैंने +1 किया तो व्हॉट्सएप भूल गया। +1 :( हो गया! उस हाहा के बारे में क्षमा करें :)
मेहरदाद

4
tail -rOSX के लिए विशिष्ट है, और न्यूलाइन-सीमांकित इनपुट को उलट देता है, शून्य-सीमांकित इनपुट नहीं। आपका दूसरा समाधान बिल्कुल भी काम नहीं करता (आप इनपुट को पाइप कर रहे हैं ls, जिसकी कोई परवाह नहीं है); कोई आसान तय नहीं है जो इसे मज़बूती से काम करेगा।
गिल्स एसओ- बुराई को रोकना '

1

आपके उदाहरण में आप कई फ़ाइलों पर लूपिंग कर रहे हैं, लेकिन मुझे यह प्रश्न अपने अधिक सामान्य शीर्षक के कारण मिला, जो किसी सरणी पर लूपिंग को कवर कर सकता है, या किसी भी क्रम के आधार पर उलट सकता है।

यहाँ है कि Zsh में कैसे करें:

यदि आप किसी सरणी में तत्वों पर लूप कर रहे हैं, तो इस सिंटैक्स का उपयोग करें ( स्रोत )

for f in ${(Oa)your_array}; do
    ...
done

Oअगले झंडे में निर्दिष्ट आदेश के विपरीत; aसामान्य सरणी क्रम है।

जैसा कि @Gilles ने कहा, Onआपकी ग्लॉब्ड फाइल्स को ऑर्डर करेगा, जैसे कि my/file/glob/*(On)। ऐसा इसलिए Onहै क्योंकि "रिवर्स नेम ऑर्डर है।"

Zsh तरह झंडे:

  • a सरणी क्रम
  • L फ़ाइल की लंबाई
  • l लिंक की संख्या
  • m सुधार की तारीख
  • n नाम
  • ^oरिवर्स ऑर्डर ( oसामान्य ऑर्डर है)
  • O उल्टे क्रम

उदाहरण के लिए, https://github.com/grml/zsh-lovers/blob/master/zsh-lovers.1.txt और http://reasoniamhere.com/2014/01/11/outrageously-useful-tips- देखें टू-गुरु-अपने-Z-खोल /


0

Mac OSX tacकमांड का समर्थन नहीं करता है । @Tcdyl द्वारा समाधान तब काम करता है जब आप एक कमांड को forलूप में बुला रहे हैं । अन्य सभी मामलों के लिए, इसके चारों ओर जाने का सबसे सरल तरीका निम्नलिखित है।

यह दृष्टिकोण आपके फ़ाइलनाम में नई सूचियाँ होने का समर्थन नहीं करता है। अंतर्निहित कारण यह है कि tail -rइसके इनपुट को न्यूलाइन द्वारा सीमांकित किया गया है।

for i in `ls -1 [filename pattern] | tail -r`; do [commands here]; done

हालांकि, न्यूलाइन सीमा के आसपास जाने का एक तरीका है। यदि आप जानते हैं कि आपके फ़ाइल नाम में एक निश्चित वर्ण नहीं है (कहते हैं, '='), तो आप trइस वर्ण को बनने के लिए सभी नई सूचियों को बदलने के लिए उपयोग कर सकते हैं और फिर छँटाई कर सकते हैं। परिणाम इस प्रकार दिखेगा:

for i in `find [directory] -name '[filename]' -print0 | tr '\n' '=' | tr '\0' '\n'
| tail -r | tr '\n' '\0' | tr '=' '\n' | xargs -0`; do [commands]; done

नोट: आपके संस्करण के आधार पर tr, यह '\0'एक चरित्र के रूप में समर्थन नहीं कर सकता है । यह आमतौर पर सी में स्थान बदलकर सी के आसपास काम किया जा सकता है (लेकिन मुझे याद नहीं है कि वास्तव में कैसे ठीक है, क्योंकि इसे एक बार ठीक करने के बाद अब यह मेरे कंप्यूटर पर काम करता है)। यदि आपको कोई त्रुटि संदेश मिलता है, और आपको वर्कअराउंड नहीं मिल सकता है, तो कृपया इसे टिप्पणी के रूप में पोस्ट करें, इसलिए मैं आपको इसका निवारण करने में मदद कर सकता हूं।


0

एक आसान तरीका ls -r@David Schwartz द्वारा उल्लेख किया गया है

for f in $(ls -r /var/logs/foo*.log); do
    bar "$f"
done

-4

इसे इस्तेमाल करे:

for f in /var/logs/foo*.log; do
bar "$f"
done

मुझे लगता है कि यह सबसे सरल तरीका है।


3
सवाल " forरिवर्स ऑर्डर में लूप " के लिए पूछा गया ।
मैनटवर्क
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.