Comment puis-je imprimer des lignes depuis un file vers l'arrière (sans utiliser "tac")?

Je veux imprimer les lignes d'un file à l'envers sans utiliser la command tac . Y at-il une autre solution pour faire une telle chose avec bash?

Utiliser sed pour émuler tac :

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

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

via awk une doublures

Avec ed :

 ed -s infile <<IN g/^/m0 ,p q IN 

Si vous êtes sur BSD / OSX (et espérons bientôt sur GNU / linux aussi que ce sera POSIX ):

 tail -r infile 

Comme vous avez demandé de le faire en bash, voici une solution qui ne fait pas usage de awk, sed ou perl, juste une fonction bash:

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

La sortie de

 echo 'a b c d ' | reverse 

est

 d c b a 

Comme prévu.

Mais attention, les lignes sont stockées en memory, une ligne dans chaque instance récursivement appelée de la fonction. Donc, attention aux gros files.

Vous pouvez le passer à travers:

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

L' awk préfixe chaque ligne avec le numéro de ligne suivi d'un espace. Le sort inverse l'ordre des lignes en sortingant sur le premier champ (numéro de ligne) dans l'ordre inverse, style numérique. Et le sed enlève les numéros de ligne.

L'exemple suivant montre ceci en action:

 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' 

Il sort:

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

En perl:

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

Solution uniquement BASH

lire le file dans le tableau bash (une ligne = un élément du tableau) et imprimer le tableau dans l'ordre inverse:

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

Bash, avec mapfile mentionné dans les commentaires de fiximan, et en fait une version probablement meilleure:

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

Sa performance est fondamentalement comparable à la solution sed , et devient plus rapide lorsque le nombre de lignes demandées diminue.

 awk '{print NR" "$0}' | sort -nr