Satırları dosyadan geriye doğru nasıl yazdırabilirim (“tac” kullanmadan)?


Yanıtlar:


33

sedTaklit etmek için kullanma tac:

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

3
Bu iyi bir çözüm, ancak bunun nasıl daha iyi olacağı konusunda bazı açıklamalar.
Chen Levy

10
Ünlü sedbir tek astar. Bkz. "36. Satırların ters sıralaması (" tac "Unix komutunu taklit edin)." içinde Ünlü Sed Tek Gömlekleri Açıklaması nasıl çalıştığını tam bir açıklama için.
Johnsyweb

6
Belki de dikkat çekmeye değer: "Bu iki gömlek, aslında çok fazla bellek kullanıyor çünkü yazdırmadan önce tüm dosyayı ters sırada tutuyorlar. Büyük dosyalar için bu gömlekleri kullanmaktan kaçının."
Bay Shickadance 17:11

Öyleyse diğer tüm cevapları da verin (belki biri hariç sort- geçici bir dosya kullanması ihtimali vardır).
Random832

1
Tac'in normal dosyalar için daha hızlı olduğuna dikkat edin, çünkü dosyayı geriye doğru okur. Borular için diğer çözümlerle aynı şeyi yapması gerekir (bellekte veya geçici dosyalarda tutun), bu nedenle önemli ölçüde daha hızlı değildir.
Stéphane Chazelas 14:12


6

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

yoluyla bir gömlekleri awk


4
Daha kısa bir:awk 'a=$0RS a{}END{printf a}'
ninjalj

@ ninjalj: daha kısa olabilir, ancak dosya boyutu büyüdükçe çok yavaşlar. 2 dakika 30 saniye bekledikten sonra pes ettim. but your first perl reverse <> `sayfadaki en iyi / en hızlı cevap (benim için), bu awkcevaptan 10 kat daha hızlı (tüm awk anseres aynı, zaman dilimi aynı)
Peter.O

1
Veyaawk '{a[NR]=$0} END {while (NR) print a[NR--]}'
Stéphane Chazelas 14:12

5

Bunu bash yapmak istedi, işte awk, sed veya perl, sadece bash işlevini kullanmayan bir çözüm:

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

Çıktısı

echo 'a
b
c
d
' | reverse

olduğu

d
c
b
a

Beklenildiği gibi.

Fakat satırların bellekte saklandığından ve fonksiyonun tekrarlanan adıyla her birinde bir satır olduğundan emin olun. Büyük dosyalara çok dikkat et.


1
Diğer cevapların en yavaşına kıyasla dosya boyutu arttıkça, hızlı bir şekilde pratikte yavaşlar ve önerdiğiniz gibi hafızayı oldukça kolay patlatır: * bash özyinelemeli işlev ... ama ilginç bir fikir. Bölümlendirme hatası *
Peter.O

4

Boru ile yapabilirsiniz:

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

awkHer satırın satır numarası ve ardından boşluk bulunan ön ekler. sortTers, sayısal bir tarzda ilk alan (satır sayısı) sıralayarak hatları sırasını tersine çevirir. Ve sedşeritler satır numaralarını keser.

Aşağıdaki örnek bunu eylem halinde gösterir:

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'

Çıktıları:

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

Tamam. Teşekkürler! Bunu deneyeceğim. Ve yorumlarınız için teşekkürler!

5
cat -ngibi davranırawk '{print NR" "$0}'
Chen Levy

2
Bence bu Schwartzian dönüşümü ya da
decore

Bu genel yaklaşım, görev bellekte yapmak için çok büyükse, diskteki dosyaları kullanarak bu tür işlemlerde iyidir. Borular yerine adımlar arasında geçici dosyalar kullandıysanız, hafızada daha yumuşak olabilir.
mc0e,

1

Perl'de:

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

2
veya daha kısaperl -e 'print reverse<>'
ninjalj

2
(Aslında, daha kısa bir tane var, ama bu gerçekten tanık, onun berbatlık çirkin: perl -pe '$\=$_.$\}{')
ninjalj

@ Frederik Deweerdt: Hızlı, ama ilk sırayı kaybeder ... @ ninjalj: reverse<)hızlı: iyi! ama "gerçekten çirkin" olanı satır sayısı arttıkça oldukça yavaştır . !! ....
Peter.O

@ Peter.O -norada gereksiz, teşekkürler.
Frederik Deweerdt

Bu konuda güzel olan şey, dosyanın içeriğinin mutlaka belleğe okunmaması gerektiğidir (muhtemelen topakları hariç sort).
Kusalananda

0

Yalnızca BASH çözümü

dosyayı bash dizisine (bir satır = dizinin bir elemanı) okuyun ve diziyi ters sırada yazdırın:

i=0 

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


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

Girintili çizgilerle deneyin ... philfr'ın sürümü biraz daha iyi ama hala veeeery slooooow gerçekten, metin işleme gelince, asla kullanmayın while..read.
don_crissti

Kullanım IFS=''ve read -rkaçışların her türlü önlemek ve yukarı vidalama gelen IFS çıkarılmasını sondaki için. Ben bash mapfile ARRAY_NAMEyerleşiminin diziler halinde okumak için daha iyi bir çözüm olduğunu düşünüyorum .
Arthur2e5

0

Bash, mapfilefiximan'a yaptığı açıklamada bahsetti ve aslında daha iyi bir versiyonuyla:

# 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
}

Performansı temel olarak sedçözümle karşılaştırılabilir ve istenen hat sayısı azaldıkça hızlanıyor.


0
Simple do this with your file to sort the data in reverse order, and it should be unique.

sed -n '1h; 1d; G; h; $ p'


0
  • Nl ile satırları numaralandır
  • numarasına göre ters sırada sırala
  • sed ile sayıları kaldırın

burada gösterildiği gibi:

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

Sonuç:

c
a
f
e

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.