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