Skip to content
 

Print lines in reverse order

On a popular Linux magazine, one of the writers asked people to come up with different ways to print the lines of a file in reverse order, ie like what the program tac does.

So here are some ways to do that, almost all of which are silly, useless, crazy, dangerous and inefficient. You have been warned.

Some can work with both standard input and a real file, some only work with a real file (the examples all use a file). The shell examples use some bash-specific features for convenience, although they could all be rewritten to use only standard constructs (except the one that uses arrays).

No explanations to avoid spoiling the fun (some are obvious though).

tac file
cat -n file | sort -k1,1rn | cut -f 2-
awk '{a[NR]=$0} END {for(i=NR;i>0;i--)print a[i]}' file
perl -e 'print reverse <>' file
perl -ne 'push @a,$_; print reverse @a if eof' file
sed '1!G;h;$!d' file
awk '{out = $0 s out; s = RS} END {print out}' file
i=0
while IFS= read -r arr[i]; do ((i++)); done < file
for((j=i-1;j>=0;j--)); do printf "%s\n" "${arr[$j]}"; done
sed ':a;$!{N;ba;}; s/$/\x1/; 
     :b; s/\n\{0,1\}\([^\n]*\)\x1\(.*\)/\x1\2\n\1/; /^\x1/!bb; 
     s/\x1\n//' file
i=0
while true; do
  if gawk -v n="$i" 'NR==n{exit}END{print;exit NR-1}' file; then
    break
  else
    i=$?
  fi
done
# NEVER do this
touch outfile
while IFS= read -r line; do
  { rm outfile; { printf "%s\n" "$line"; cat; } > outfile; } < outfile
done < file
cat outfile
rm outfile
i=0
while IFS= read -r line; do
  ((i++))
  printf "%s\n" "$line" > "$i".txt
done < file

while [ $i -gt 0 ]; do
  cat $i.txt
  ((i--))
done

rm *.txt
# same idea as above, unnecessarily extra-complicated...
shift_names() {
  n=$1
  while [ $n -gt 0 ]; do
    mv "$n.txt" "$((n+1)).txt"
    ((n--))
  done
}

i=0
while IFS= read -r line; do
  shift_names $i
  printf "%s\n" "$line" > 1.txt
  ((i++))
done < file

for((j=1;j<=i;j++)); do
  cat $j.txt
done

rm *.txt
{
printf '<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
  <soapenv:Body>
    <a:sort
         soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" 
         xmlns:a="http://linuxtoolbox.kwfgrid.net">  
      <a:params>-k1,1nr</a:params>
      <a:value>'

recode utf8..xml < file | sed = | sed 'N;s/\n/ /' | awk -v ORS='&#xa;' 1

printf '</a:value>
    </a:sort>
  </soapenv:Body>
</soapenv:Envelope>'
} | curl -s -o - -d @- \
-H 'Content-Type: application/soap+xml;charset=utf-8' \
-H 'SOAPAction: ""' \
'http://www.gridworkflow.org:8080/linuxtoolbox/services/Sort' |\
xmlstarlet sel -T -t -v '//sortReturn' | perl -pe 's/^\d+ //'

If you can think of other ways (for example based on different ideas, more convoluted, or using other programming languages, etc.) contributions are welcome.

Update 02/01/2011 - here's another one:

LC_ALL=C awk -v x="0" '{y += length($0) + 1; x = y RS y FS x}END{print substr(x, index(x, RS) + 1)}' file | \
while IFS=" " read -r a b; do
  dd skip=$b count=$((a - b)) bs=1 2>/dev/null < file
done

One Comment

  1. shantiq says:

    Thanx amazing

    tac and perl work a treat

    Downloaded Messages in FB Data which gives you a file called messages.htm in reverse chronological order ... this cures that in under a second ... copy section you want sve as .txt and badaboom