Utiliser less comme visionneur universel

La commande less(1) (du moins telle qu’elle est installé avec le paquet debian du même nom) possède une petite fonctionnalité sympathique : lesspipe(1)
Elle permet d’ouvrir un fichier non texte avec un visionneur externe, et de renvoyer la sortie à less.
N’importe quel programme qui extrait des données d’un document et les renvoie dans la console au format texte peut être utilisé.

Pour celà il suffit de définir la variable LESSOPEN telle que LESSOPEN=| /usr/bin/lesspipe %s

lessfile(1) fait de même, mais utilise un fichier temporaire au lieu des tubes (« | »). Elle utilise en plus la variable LESSCLOSE pour supprimer le fichier à la fin.

Ce sont les scripts /usr/bin/lesspipe et /usr/bin/lessfile qui se chargent de tout. Ces scripts sont identiques. Je montrerai l’exemple de lesspipe ici.
Quand on l’appelle sans arguments :

$ lesspipe export LESSOPEN="| /usr/bin/lesspipe %s"; export LESSCLOSE="/usr/bin/lesspipe %s %s";

Donc il suffit de rajouter une ligne dans ~/.bashrc :

Et déjà, less permet de lire le contenu des archives (arj, tar, bz2, deb, iso, bin, raw, rar, rpm, gz, tar, zip…).
Si l’archive contient plusieurs fichiers, less affiche la liste des fichiers. Si c’est un simple fichier texte compréssé (une archive dans /var/log par exemple), less affichera le contenu du fichier !
Il affiche aussi les .doc et .pdf, ainsi que les données des images (gif, jpg, png, tif…)

Si vous avez des problèmes d’encodage, rajoutez export LESSCHARSET=latin9 dans votre .bashrc. :smt002

S’il vous manque un paquet pour le visionner. less vous affichera un message, disant que tel ou tel paquet est manquant. Vous pouvez aussi regarder le script /usr/bin/lesspipe pour voir quels visionneurs il utilise.

Mais ce n’est pas tout, le script permet de rajouter (ou changer) les règles. Il suffit de créer un fichier ~/.lessfilter dans lequel on rajoute ce que l’on veut.
Par exemple :

[code]#!/bin/sh

~/.lessfilter : règles supplémentaires pour lesspipe

pour visionner le contenu des dossiers

if [ -d “$1” ];then
ls -la $1
exit 0
fi

case echo "$1" | tr '[:upper:]' '[:lower:]' in

lire les odt (nécessite odt2txt)

*.odt)
odt2txt “$1”
;;

bonus pour les images

.jpg|.jpeg|.gif|.bmp|*.png)
# voir la description de l’image
# c’est le comportement par défaut de lesspipe (nécessite imagemagick)
identify “$1” > /tmp/lessout
# voir l’image en ASCII en dessous (nécessite caca-utils)
# il faut ajouter l’option -r à less pour voir la couleur (export LESS=-r)
img2txt “$1” >> /tmp/lessout
# récupère la description avec l’image en ASCII dessous :
cat /tmp/lessout
rm /tmp/lessout
;;

Voir les tags des mp3 (nécessite mp3info)

*.mp3)
mp3info “$1”
;;

Voir les tags des ogg (nécessite avinfo)

*.ogg)
avinfo “$1”
;;

infos sur les videos (nécessite avinfo)

.mpg|.avi|*.wmv)
avinfo --far “$1”
;;
*)
exit 1
esac

exit 0
[/code]
Et on peut encore en rajouter d’autres… :smt003
N’hésitez pas à poster vos trouvailles !

Remerciements : l’affichage des astuces au hasard sur la page d’acceuil de DLFP, qui m’a amené sur http://linuxfr.org/forums/47/24920.html

Je n’ai pas trouvé de moyens d’avoir une coloration syntaxique avec lesspipe (à part un script qui la ferait à coups de sed :smt107 ). J’ai donc fait autrement :

  • Pour les pages man : export PAGER=`which most` (nécessite most)

  • Pour le code, le vrai : alias more='/usr/share/vim/vimcurrent/macros/less.sh' (nécessite vim)

Je savais que less possédait de nombreuses capacités, mais je ne m’y étais pas intéressé outre mesure. Mais présenté comme ça, je vais devoir mettre un terme à mon ignorance et me pencher sur le sujet.

Excellente astuce ! :laughing: :laughing: :laughing:

EDIT : Je viens de vérifier la création de ${HOME}/.lessfilter va remplacer les scripts prédéfinis donc il faut réimplémenter chaque format. :frowning:

Le script lesspipe lit le script .lessfilter.
Si .lessfilter renvoie 0 (exit 0) lesspipe se termine.
Sinon (exit 1) lesspipe applique ses règles. :smt002

Le dit code dans lesspipe :

[code]# Allow for user defined filters
#if [ -x ~/.lessfilter -a -O ~/.lessfilter ]; then
if [ -x ~/.lessfilter ]; then # si .lessfilter existe (et est exécutable)
~/.lessfilter “$1” # on le lance
if [ $? -eq 0 ]; then # si il renvoie 0
if [ $BASENAME = $LESSFILE ]; then
if [ -s $TMPFILE ]; then
echo $TMPFILE
else
rm -f $TMPFILE
fi
fi
exit 0 # on sort
fi
fi

sinon on continue…[/code]

Donc, avec le .lessfilter que j’ai posté, je peux lire les pdf, les archives, tout ça :exclamation:

Bon, finalement, on peut tout faire avec less, y compris la coloration :

  • Pour les pages de manuel, il faut definir les variables LESS_TERMCAP_*. Exemple pompé dans le wiki archlinux :

export LESS_TERMCAP_mb=$'\E[01;31m' # début de blink export LESS_TERMCAP_md=$'\E[01;31m' # début de gras export LESS_TERMCAP_me=$'\E[0m' # fin export LESS_TERMCAP_so=$'\E[01;44;33m' # début de la ligne d`état export LESS_TERMCAP_se=$'\E[0m' # fin export LESS_TERMCAP_us=$'\E[01;32m' # début de souligné export LESS_TERMCAP_ue=$'\E[0m' # fin

  • Pour le code, il suffit d’utiliser highlight, fourni avec le paquet du même nom. Mon nouveau .lessfilter :

[code]#!/bin/sh

~/.lessfilter: add commands for lesspipe

case echo "$1" | tr '[:upper:]' '[:lower:]' in
*.odt)
if [ -x which odt2txt ]; then odt2txt “$1”;
else echo “No odt2txt available”; fi
;;

    *.mp3)
    if [ -x `which eyeD3` ]; then eyeD3 "$1";
    else echo "No eyeD3 available"; fi
    ;;

    *.ogg)
    if [ -x `which avinfo` ]; then avinfo "$1";
    else echo "No avinfo available"; fi
    ;;

    *.mpg|*.avi|*.wmv)
    if [ -x `which avinfo` ]; then avinfo --far "$1";
    else echo "No avinfo available"; fi
    ;;

    *.c|*.h|*.py|*.pl)
    if [ -x `which highlight` ]; then highlight -A "$1";
    else echo "No highlight available"; fi
    ;;

    *makefile)
    if [ -x `which highlight` ]; then highlight -S qmake -A "$1";
    else echo "No highlight available"; fi
    ;;

    *)
    case `file "$1"` in
            *directory)
            ls -la "$1"
            ;;

            *POSIX*shell*script*executable)
            if [ -x `which highlight` ]; then highlight -S bash -A "$1";
            else echo "No highlight available"; fi
            ;;

            *)
            exit 1
    esac

esac

exit 0[/code]

Plus besoin de s’énerver sur les keybindings de most, ou sur vim qui ne veut pas copier la selection dans le presse papier…

Merci pour la coloration dans less! Pour fêter ça j’ai purgé most.

Tu utilises quel version de vim?
Avec vim-nox, je n’y arrivais pas non plus, j’ai dû installer vim-gtk pour y arriver,
tu vas me dire que c’est un peu sortir un marteau pour écraser une mouche, mais bon.
Pour copier dans le clipboard je préfixe mes commandes de selection avec "*
Par exemple "*yy copie la ligne courante dans le clipboard, ça marche aussi en mode visuel.
J’ai pas encore testé ton visualiseur universel, je n’utilisais lesspipe que pour les textes gunzipé
jusqu’à maintenant, il va être temps que j’exploite tout son potentiel.

[quote=“eol”]Pour copier dans le clipboard je préfixe mes commandes de selection avec "*
Par exemple "*yy copie la ligne courante dans le clipboard, ça marche aussi en mode visuel.[/quote]
Je parlais du copier-coller à la souris en fait. Mauvaise habitude dont je ne me suis pas encore affranchi… :slightly_smiling:

Si c’est juste pour ça, il y a zless aussi. Qui je crois a pour seul avantage par rapport à lesspipe, que tu dois le retrouver sur toutes les distribs…

Avec vim-gtk, la sélection de la souris va aussi dans le clipboard, je l’utilise pas car elle a tendance à me copier aussi
les numéros de ligne avec, ce qui n’est pas le but recherché.

[quote=“eol”]je l’utilise pas car elle a tendance à me copier aussi
les numéros de ligne avec, ce qui n’est pas le but recherché.[/quote]Tu peux oublier ce que j’ai écrit, je me repenché sur la question et en ajoutant :set mouse=a
dans mon ~/.vimrc, ça résout le problème.

Bien vu :smt023

Je déterre ce topic, car il m’a été bien utile dans m’a tentative de configurer less, pour ma part j’arrive à un .lessfilter qui donne ça :

[code]#!/bin/bash

==============================================================================

Nom : ~/.lessfilter

Description : Script ajoutant des commandes à lesspipe. Lesspipe doit être

activer dans ~/.bashrc via <eval $(lesspipe)>

Création : 17-03-2013

Copyright © 2013 Aurélien

This work is free. You can redistribute it and/or modify it under the

terms of the Do What The Fuck You Want To Public License, Version 2,

as published by Sam Hocevar. See http://www.wtfpl.net/ for more details.

// NOTES //

Le script lesspipe lit le script .lessfilter.

Si .lessfilter renvoie 0 (exit 0) lesspipe se termine.

Sinon (exit 1) lesspipe applique ses règles.

Une fonction “less” ajoutée à .bashrc permet de gérer l’encodage

export LESSCHARSET=latin9

Pour + de précisions voir :

- http://www.debian-fr.org/utiliser-less-comme-visionneur-universel-t16714.html

- http://meandubuntu.wordpress.com/2009/01/08/adding-more-to-less/

- http://forums.archlinux.fr/viewtopic.php?f=6&t=1362&view=next

- http://xbuntu.blogspot.fr/2010/09/color-highlighting-in-less.html

- http://www.cyberciti.biz/faq/linux-unix-colored-man-pages-with-less-command/

- https://gist.github.com/nandhp/1236119

==============================================================================

case echo "$1" | tr '[:upper:]' '[:lower:]' in
.odt)
if [ -x which odt2txt ]; then
odt2txt "$1"
else
echo "No odt2txt available"
fi ;;
.mp3)
if [ -x which eyeD3 ]; then
eyeD3 "$1"
else
echo "No eyeD3 available"
fi ;;
.mpg|.avi|
.wmv|
.ogm|.ogg|.mkv)
if [ -x which avinfo ]; then
avinfo --far "$1"
else
echo "No avinfo available"
fi ;;
.C|.H|.ac|.am|.autoconf|.bib|.bison|.c|.caml|.cc|.changelog|
.cls|.cpp|
.cs|.csh|.csharp|.css|.desktop|.diff|.docbook|.dtx|
.eps|.fixed-fortran|
.flex|.fortran|.free-fortran|.glsl|.h|.haxe|
.hh|.hpp|
.htm|.html|.hx|.in|.ini|.java|.javascript|.js|.kcfg|
.kdevelop|.kidl|.ksh|.l|.lang|.langdef|.latex|.ldap|.ldif|.lex|
.lgt|.ll|.log|.logtalk|.lsm|.lua|.m4|.makefile|.ml|.mli|.moc|
.outlang|.pas|
.pascal|.patch|.perl|.php|.php3|.php4|.php5|.pl|
.pm|.postscript|
.prolog|.properties|.ps|.py|.python|.rb|.rc|
.ruby|.sh|.shell|.sig|.sl|.slang|.slsh|.sml|.spec|.sql|.sty|
.style|.syslog|
.tcl|.tcsh|.tex|.tk|.txt|.ui|.xhtml|.xml|.y|
.yacc|.yy)
if [ -x “which source-highlight” ]; then
source-highlight -n -f esc -i "$1"
else
# rend la main à lesspipe
exit 1
fi ;;
)
case file "$1" in
directory)
echo -e “”$1" est un répertoire > ouverture avec lesspipe\n"
echo "Contenu : "
echo "================================================================================"
ls -lha --group-directories-first "$1"
echo “================================================================================” ;;
# Gestion des scripts sans extension (shell, ruby, python, etc)
scripttext
executable
)
if [ -x “which source-highlight” ]; then
source-highlight -n -f esc -i "$1"
else
# rend la main à lesspipe
exit 1
fi ;;
*)
# rend la main à lesspipe
exit 1
esac
esac

exit 0[/code]

Il permet de gérer les fichiers .odt .mpg .avi .wmv .ogm .ogg .mkv, comme le .lessfilter de Kna, mais propose la coloration syntaxique pour plus de types de fichier. Pour cela j’utilise le paquet source-highlight au lieu de highlight (je ne saurai pas bien vous dire la différence par contre…)

En plus pour gérer l’encodage des fichiers ISO-8859 ponctuellement j’ai ajouté cette fonction à mon .bashrc, ce qui permet d’éviter de définir en dur LESSCHARSET dans .bashrc (sinon avec latin9, ça flingue l’affichage des pages de man…)

less() { case `file "$1"` in *ISO-8859*) export LESSCHARSET=latin9 /usr/bin/less "$1" unset LESSCHARSET ;; *) /usr/bin/less "$1" ;; esac }

Par contre tout ce bricolage ralenti sans doute less sur les gros fichiers, mais je n’ai pas testé, pour un usage courant ça à l’air utilisable.

Moi j’ai mis dans mon .bashrc :

Sinon, mon script a évolué aussi depuis (j’ai écrit un lesspipe directement, car utilisé sur d’autres distributions que debian, qui n’ont pas de .lessfilter, mais qui m’ont bien inspiré). Je l’ai fait au fil de l’eau, mais vu que ça fait un moment que je n’y ai pas touché, ton déterrage m’a fait penser qu’il serait temps de le poster :

#!/bin/sh
# input preprocessor for less

# print LESSOPEN variable, when called without args
# (use it with absolute path)
if [ $# -eq 0 ]; then
        echo "LESSOPEN=\"|$0 %s\""
        #echo "LESSCHARSET=latin9"
        if env | grep -q '^LESS=' ; then
                if ! echo $LESS | grep -q '\-R' ; then
                        echo "LESS=\"-R $LESS\""
                fi
        else
                echo "LESS=-R"
        fi
        echo "export LESS LESSOPEN LESSCHARSET"
        exit
fi

# Check usage
if [ $# -gt 1 ]; then
        echo "Usage: Don't use it directly"
        echo 'Launch "eval $(/path/to/lesspipe.sh)" to use it with less'
fi

# We just determine file type of $1
# and determine which viewer is appropriate
case "$(file -Lb "$1")" in
# Folder
directory)
        ls -la "$1" 2>/dev/null ;;

# Archive
POSIX[[:space:]]tar[[:space:]]archive*)
        tar tvvf "$1" 2>/dev/null ;;
gzip[[:space:]]compressed[[:space:]]data*) # Test if tar or man 
        if gzip -dc "$1" | file - | grep -q 'tar archive' ; then
                tar tvvf "$1" 2>/dev/null
        elif gzip -dc "$1" | file - | grep -q 'roff' ; then
                gzip -dc "$1" | nroff -S -mandoc -
        else
                gzip -dc "$1" 2>/dev/null
        fi ;;
bzip2[[:space:]]compressed[[:space:]]data*)
        if bzip2 -dc "$1" | file - | grep -q 'tar archive' ; then
                tar tvvf "$1" 2>/dev/null
        elif bzip2 -dc "$1" | file - | grep -q 'roff' ; then
                bzip2 -dc "$1" | nroff -S -mandoc -
        else
                bzip2 -dc "$1" 2>/dev/null
        fi ;;
cpio[[:space:]]archive)
        which cpio >/dev/null && cpio -it < "$1" 2>/dev/null ;;
[Xx][Zz][[:space:]]compressed[[:space:]]data*)
        if xz -dc "$1" | file - | grep 'tar archive' ; then
                xz -dc "$1" | tar tvvf - 2>/dev/null
        else
                xz -dc "$1" 2>/dev/null
        fi ;;
data) # Test if lzma archive
        if xz -t "$1" ; then
                if xz -F lzma -dc "$1" | file - | grep 'tar archive' ; then
                        xz -F lzma -dc "$1" | tar tvvf - 2>/dev/null
                else
                        xz -F lzma -dc "$1" 2>/dev/null
                fi
        else
                echo "Unrecognized file"
        fi ;;
ISO[[:space:]]9660[[:space:]]CD-ROM[[:space:]]filesystem[[:space:]]data*)
        if which isoinfo >/dev/null ; then
                echo "$1:" ; isoinfo -d -i "$1"
                echo
                echo '***Contents:' ; isoinfo -f -i "$1"
        fi ;;
Zip[[:space:]]archive[[:space:]]data*)
        unzip -l "$1" 2>/dev/null ;;
RAR[[:space:]]archive[[:space:]]data*)
        which unrar >/dev/null && unrar l "$1" 2>/dev/null ;;

# Distributions Packages
Debian[[:space:]]binary[[:space:]]package*)
        if which dpkg >/dev/null ; then
                echo "$1:" ; dpkg --info "$1"
                echo
                echo '*** Contents:' ; dpkg-deb --contents "$1"
        else
                ar p "$1" data.tar.gz | tar tzvf -
        fi ;;
RPM*)
        if which rpm >/dev/null ; then
                echo "$1:" ; rpm -q -i -p "$1"
                echo
                echo '*** Contents:' ; rpm -q -l -p "$1"
        elif which rpm2cpio >/dev/null ; then
                rpm2cpio "$1" | cpio -it
        fi ;;

# Printable documents
PDF[[:space:]]document*)
        which pdftotext >/dev/null && pdftotext "$1" - 2>/dev/null ;;
PostScript[[:space:]]document*)
        if which pdftotext >/dev/null && which ps2pdf >/dev/null ; then
                ps2pdf "$1" > /tmp/less-$$ 2>/dev/null
                pdftotext /tmp/less-$$ - 2>/dev/null
                rm -f /tmp/less-$$
        fi ;;
TeX[[:space:]]DVI[[:space:]]file*)
        which dvi2tty >/dev/null && dvi2tty "$1" >/dev/null ;;

# Editable documents
LaTeX*document[[:space:]]text)
        which highlight >/dev/null && highlight -S tex -O ansi "$1" 2>/dev/null ;;
HTML[[:space:]]document[[:space:]]text)
        which highlight >/dev/null && highlight -S html -O ansi "$1" 2>/dev/null ;;
OpenDocument[[:space:]]Text)
        which odt2txt >/dev/null && odt2txt "$1" 2>/dev/null ;;
CDF[[:space:]]V2[[:space:]]Document*) # MS Office document
        if echo "$1" | grep -q '\.doc$' ; then
                which catdoc >/dev/null && catdoc "$1" 2>/dev/null
        elif echo "$1" | grep -q '\.xls$' ; then
                which xls2csv >/dev/null && xls2csv "$1" 2>/dev/null
        fi ;;

# text
*perl*script*text*)
        which highlight >/dev/null && highlight -S perl -O ansi "$1" 2>/dev/null ;;
*python*script*text*)
        which highlight >/dev/null && highlight -S python -O ansi "$1" 2>/dev/null ;;
*sh*script*text*)
        which highlight >/dev/null && highlight -S Bash -O ansi "$1" 2>/dev/null ;;
*[pP][hH][pP]*script*text*)
        which highlight >/dev/null && highlight -S php -O ansi "$1" 2>/dev/null ;;
*C*program*text)
        which highlight >/dev/null && highlight -S c -O ansi "$1" 2>/dev/null ;;
*text)
        if echo "$1" | grep -q 'Makefile' ; then
                which highlight >/dev/null && highlight -S qmake -O ansi "$1" 2>/dev/null
        else
                cat "$1" 2>/dev/null
        fi ;;

# Images
JPEG[[:space]]image[[:space:]]data*)
        which identify >/dev/null && identify "$1" 2>/dev/null
        which jp2a >/dev/null && jp2a --color "$1" 2>/dev/null ;;

*image[[:space:]]data*)
        which identify >/dev/null && identify "$1" 2>/dev/null
        which jp2a >/dev/null && convert "$1" jpg:- 2>/dev/null | jp2a --color - 2>/dev/null ;;

# Others
# *)
#       cat "$1" ;;

esac