मैं फ़ाइल को पीछे से ("टैक" का उपयोग किए बिना) कैसे प्रिंट कर सकता हूं?


26

मैं tacकमांड का उपयोग किए बिना एक फ़ाइल से लाइनों को पीछे की तरफ प्रिंट करना चाहता हूं । क्या बैश के साथ ऐसा करने का कोई और उपाय है?


जवाबों:


33

sedअनुकरण करने के लिए उपयोग करना tac:

sed '1!G;h;$!d' ${inputfile}

3
यह एक अच्छा समाधान है, लेकिन यह कैसे बेहतर होगा इसके लिए कुछ स्पष्टीकरण।
चेन लेवी

10
यह एक प्रसिद्ध sedवन-लाइनर है। "36. लाइनों का उल्टा क्रम देखें (" टैक "यूनिक्स कमांड) का अनुकरण करें।" में प्रसिद्ध Sed एक-लाइनर समझाया यह कैसे काम करता की पूरी जानकारी के लिए।
11:36 पर जॉन्सवेब

6
शायद ध्यान देने योग्य: "ये दो वन-लाइनर्स वास्तव में बहुत अधिक मेमोरी का उपयोग करते हैं क्योंकि वे पूरी फाइल को प्रिंट करने से पहले रिवर्स ऑर्डर में बफर में रखते हैं। बड़ी फ़ाइलों के लिए इन वन-लाइनर्स से बचें।"
श्री शुकादांस

तो सभी अन्य उत्तर दें (शायद एक का उपयोग करके sort- एक मौका है कि यह एक अस्थायी फ़ाइल का उपयोग करेगा)।
रैंडम 832

1
ध्यान दें कि नियमित फ़ाइलों के लिए tac तेज़ है क्योंकि यह फ़ाइल को पीछे की ओर पढ़ता है। पाइपों के लिए, इसे अन्य समाधानों (मेमोरी में या टेम्प फाइलों में पकड़) के समान ही करना है, इसलिए काफी तेज नहीं है।
स्टीफन चेजलस


6

awk '{a[i++]=$0} END {for (j=i-1; j>=0;) print a[j--] }' file.txt

एक लाइनर awk के माध्यम से


4
एक छोटा एक:awk 'a=$0RS a{}END{printf a}'
नन्हजाल

@njjalj: यह छोटा हो सकता है, लेकिन फ़ाइल का आकार बड़ा हो जाने से यह बहुत धीमा हो जाता है। मैंने 2 मिनट 30 सेकंड के इंतजार के बाद छोड़ दिया। but your first perl रिवर्स <> `यह पृष्ठ पर सबसे अच्छा / सबसे तेज़ उत्तर है (मेरे लिए), इस awkउत्तर की तुलना में 10 गुना तेज (सभी awk aseres एक ही, समय-वार हैं)
Peter.O

1
याawk '{a[NR]=$0} END {while (NR) print a[NR--]}'
स्टीफन चेज़लस

5

जैसा कि आपने इसे बाश में करने के लिए कहा, यहाँ एक समाधान है जो awk, sed या perl का उपयोग नहीं करता है, बस एक bash:

reverse ()
{
    local line
    if IFS= read -r line
    then
        reverse
        printf '%s\n' "$line"
    fi
}

का उत्पादन

echo 'a
b
c
d
' | reverse

है

d
c
b
a

जैसा सोचा था।

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


1
यह फ़ाइल के आकार में वृद्धि के साथ ही अन्य उत्तरों की सबसे धीमी गति से भी अव्यावहारिक रूप से धीमा हो जाता है, और जैसा कि आपने सुझाव दिया है, यह स्मृति को बहुत आसानी से उड़ा देता है: * पुनरावर्ती कार्य ... लेकिन इसका एक दिलचस्प विचार है।
खंडन

4

आप इसके माध्यम से पाइप कर सकते हैं:

awk '{print NR" "$0}' | sort -k1 -n -r | sed 's/^[^ ]* //g'

awkउपसर्गों लाइन संख्या के साथ प्रत्येक पंक्ति एक रिक्ति। sortउलटे क्रम, आंकिक शैली में पहले क्षेत्र (लाइन नंबर) पर छँटाई द्वारा लाइनों के आदेश को उलट देता है। और sedलाइन संख्या से स्ट्रिप्स।

निम्न उदाहरण यह क्रिया में दिखाता है:

pax$ echo 'a
b
c
d
e
f
g
h
i
j
k
l' | awk '{print NR" "$0}' | sort -k1 -n -r | sed 's/^[^ ]* //g'

यह आउटपुट:

l
k
j
i
h
g
f
e
d
c
b
a

ठीक है। धन्यवाद! मैं यह कोशिश करूँगा। और टिप्पणी के लिए धन्यवाद!

5
cat -nबहुत काम करता हैawk '{print NR" "$0}'
चेन लेवी

2
मुझे लगता है कि इसे श्वार्टज़ियन ट्रांसफ़ॉर्म , या डेकोरेट-
सॉरी

यह सामान्य दृष्टिकोण उस तरह से अच्छा है जो डिस्क पर फ़ाइलों का उपयोग करके हैंडल करता है यदि कार्य मेमोरी में यथोचित रूप से बहुत बड़ा है। यदि आप पाइप के बजाय चरणों के बीच अस्थायी फ़ाइलों का उपयोग करते हैं, तो यह मेमोरी पर जेंटलर हो सकता है।
mc0e

1

पर्ल में:

cat <somefile> | perl -e 'while(<>) { push @a, $_; } foreach (reverse(@a)) { print; }'

2
या उससे कमperl -e 'print reverse<>'
नवजाल

2
(वास्तव में, वहाँ एक छोटी एक है, लेकिन यह है वास्तव में बदसूरत गवाह अपने awfulness,: perl -pe '$\=$_.$\}{')
ninjalj

@Frederik Deweerdt: फास्ट, लेकिन यह पहली पंक्ति खो देता है ... @ नंजलज: reverse<)तेज: अच्छा है! लेकिन "वास्तव में बदसूरत" एक बहुत धीमी है क्योंकि लाइनों की संख्या बढ़ जाती है। !! ....
पीटर।

@ पीटर.ओ -nवहाँ बहुत ही शानदार था, धन्यवाद।
फ्रेडरिक डेविएरट

इस बारे में एक अच्छी बात यह है कि फ़ाइल की सामग्री को आवश्यक रूप से मेमोरी में नहीं पढ़ा जाता है (संभवतः चंक्स द्वारा छोड़कर sort)।
Kusalananda

0

BASH- केवल समाधान

बैश एरे में फ़ाइल पढ़ें (एक लाइन = एरे का एक तत्व) और रिवर्स ऑर्डर में सरणी प्रिंट करें:

i=0 

while read line[$i] ; do
    i=$(($i+1))
done < FILE


for (( i=${#line[@]}-1 ; i>=0 ; i-- )) ; do
    echo ${line[$i]}
done

इसे इंडेंटेड लाइन्स के साथ आज़माएं ... फिल्फ़ का संस्करण थोड़ा बेहतर है लेकिन फिर भी वास्तव में वॉयलरी स्लोवू है, जब यह टेक्स्ट प्रोसेसिंग की बात आती है, तो कभी उपयोग न करें while..read
don_crissti

उपयोग IFS=''और read -rसभी प्रकार के पलायन को रोकने के लिए और IFS को हटाने से इसे हटाने से पीछे हटना। मुझे लगता है कि बैश mapfile ARRAY_NAMEबिलियन हालांकि सरणियों में पढ़ने के लिए एक बेहतर समाधान है।
आर्थर

0

बैश, mapfileफिक्समैन के लिए टिप्पणियों में उल्लेख किया है, और वास्तव में एक बेहतर संस्करण है:

# last [LINES=50]
_last_flush(){ BUF=("${BUF[@]:$(($1-LINES)):$1}"); } # flush the lines, can be slow.
last(){
  local LINES="${1:-10}" BUF
  ((LINES)) || return 2
  mapfile -C _last_flush -c $(( (LINES<5000) ? 5000 : LINES+5 )) BUF
  BUF=("${BUF[@]}") # Make sure the array subscripts make sence, can be slow.
  ((LINES="${#BUF[@]}" > LINES ? LINES : "${#BUF[@]}"))
  for ((i="${#BUF[@]}"; i>"${#BUF[@]}"-LINES; i--)); do echo -n "${BUF[i]}"; done
}

इसका प्रदर्शन मूल रूप से sedसमाधान के लिए तुलनीय है , और अनुरोधित रेखाओं की संख्या कम हो जाने के कारण तेज हो जाता है।



0
  • Nl के साथ लाइनों की संख्या
  • क्रम से रिवर्स क्रम में क्रमबद्ध करें
  • संख्याओं को सेड के साथ हटाएं

जैसा यहाँ दिखाया गया है:

echo 'e
> f
> a
> c
> ' | nl | sort -nr | sed -r 's/^ *[0-9]+\t//'

परिणाम:

c
a
f
e

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