Skip to content

Linux Attitude

Le libre est un état d'esprit

Archive

Tag: Scripting

Niveau : Star Star Empty Empty Empty
Résumé : ~/.gnome2/nautilus-scripts

Aujourd'hui parlons un peu d'interface utilisateur. Vous arrive-t-il souvent de lancer la même commande sur plein de fichiers ? Avez-vous une personne de votre famille qui perd son temps à ouvrir des fichiers un par un pour faire une modification dans chaque ?

Si ces opérations sont automatisables (calculs openoffice, modification d'image, ajout d'une ligne de texte ...) alors il y a un moyen pour les rendre accessible directement depuis le navigateur de fichier. Pour cela, il suffit d'écrire un script et de le placer dans ~/.gnome2/nautilus-scripts. Essayer de bien le nommer car il apparaîtra tel quel dans le menu contextuel "Scripts" de nautilus.

Pour parler concrètement, nous allons faire un outil de réduction d'image disponible directement depuis le navigateur de fichier. Nous allons donc éditer le fichier ~/.gnome2/nautilus-scripts/ReductionPhotos qui nous permettra d'appeler imagemagick pour réduire la taille des photos sélectionnées (en ajoutant un préfixe pour ne rien perdre). Nous feront notre démo sur tous les fichiers sélectionnés à la souris pour bien montrer qu'on automatise un comportement d'utilisateur "normal".

Le script reçoit ses informations dans des variables d'environnement. La plus importante dans notre cas est NAUTILUS_SCRIPT_SELECTED_FILE_PATHS qui contient la liste des fichiers sélectionnés séparés par des retours à la ligne. Donc une petite boucle pour les traiter tous d'un coup :

echo -n "$NAUTILUS_SCRIPT_SELECTED_FILE_PATHS" | while read in_file
do
        process_file $in_file
done

Alors il se peut que le script ait des questions à poser à l'utilisateur. C'est le moment d'utiliser zenity. Un petit outil sympa, équivalent de dialog, mais bien mieux intégré dans gnome. Petite exemple avec la sélection d'un nombre dans une intervalle de 0 à 100 :

$ percent=$(zenity --scale --title="Choix du pourcentage" --text "Pourcents : " --value="50" --min-value="0" --max-value="100" --step="1")

Simple non ?

Pour traiter les images en ligne de commande, vous connaissez imagemagick. Voici la commande à utiliser dans mon cas :

convert image1.jpg -quality 80 -resize 1200 image2.jpg

Voila, on a toutes les briques pour faire le script.

#!/bin/bash
#
# Name : ReductionPhoto
# Author : peck
# Licence : GPLv2
#

set -x

#################################################
#       FONCTIONS
ask_questions ()
{
        # question communes à tous les fichieirs
        quality=$(zenity --scale --title="Choix de qualite" --text "Qualite" --value="75" --min-value="0" --max-value="100" --step="1")
        width=$(zenity --entry --title="Largeur de l'ecran" --text "Largeur" --entry-text="1200")
}

reduct()
{
        # options de reduction
        options="-quality $quality -resize $width"
echo $options >> /tmp/debug

        # sauter les non-images
        if identify "$1" >/dev/null
        then
                # convertir
                convert "$1" $options "$2"
        fi
}

#################################################
#       PROGRAMME
if [ $# -eq 0 ]; then
        zenity --error --title="Erreur" --text="Pas de fichier selectionne pour la conversion"
        exit 1
fi
if which convert 2>/dev/null
then
        true
else
        zenity --error --title="Erreur" --text="ImageMagick n'est pas installe"
        exit 1
fi

# c'est parti
ask_questions
echo -n "$NAUTILUS_SCRIPT_SELECTED_FILE_PATHS" | while read in_file
do
        ibase=$(basename "$in_file")
        idir=$(dirname "$in_file")
        out_file="$idir/r_$ibase"

        # on fait gaffe aux fichiers qu'on ecrase
        if ls "$out_file"
        then
                if zenity --question --title="Fichier existant" --text="Remplacer r_$ibase ?"
                then
                        reduct "$in_file" "$out_file"
                fi
        else
                reduct "$in_file" "$out_file"
        fi
done

# et ouala
zenity --text "Fin" --info "Reduction terminee"

À vous de faire tout ce qui vous intéresse, le reste de la doc se trouve dans la faq du site

Niveau : Star Star Empty Empty Empty
Résumé : pam_faildelay.so ; tail -F * ; dusort ;

Réduire le délai en cas d'erreur du mot de passe (très chiant pour su par exemple). Simple calcul, le délai par défaut de 2s donne 13243 ans pour bruteforcer un mot de passe de 8 lettres (26 possibilités). On peut donc se permettre de diviser ce délai par 4 pour apporter un peu de confort à l'usage :

$ vi /etc/pam.d/common-auth
# on annule le délay ajouté par pam_unix
auth    required        pam_unix.so nullok_secure nodelay
# on ajoute un délai en microsecondes
auth  optional  pam_faildelay.so  delay=500000

Attention, login vient avec son propre délai supplémentaire de 3 secondes chez debian (dans /etc/pam.d/login).

Il est possible de regarder les nouvelles lignes sur plusieurs fichiers en même temps :

$ tail -F /var/log/*

Alias pour connaître rapidement les 10 plus gros répertoire du répertoire en cours :

$ alias dusort='du --max-depth=1 | sort -rn | head -n 10'

Appeler une commande en évitant tous les alias possible (par exemple rm qui est aliasé rm -i):

# bash uniquement
$ \commande

Avancer / reculer d'un mot lors de l'édition de ligne (bash ou tout outil readline) Esc-fleche droite ou gauche.

Effacer les fichiers de plus de XX jours :

$ find . -not -ctime -XX -name "*.ncap" -exec rm {} ;

Niveau : Star Star Empty Empty Empty
Résumé : moreutils ; ts ; vidir ; mispipe ; isutf8 ; lckdo ; vipe ; ifdata ; pee

Ces commandes sont dans le paquet moreutils sur debian.

Ajouter un timestamp sur chaque ligne pour lire une commande un peu lente :

$ ./commande | ts | tail

Éditer en masse les entrées d'un répertoire (pour renommer des images par exemple) :

# Tout le répertoire
$ vidir repertoire
# Seulement les images 
$ vidir *.jpg

Retourner le code d'erreur du premier élément d'un pipe et non du dernier (très utile en scripting) :

# Retourne une erreur si $dir n'existe pas
$ mispipe "ls $dir" "tail"

Vérifier qu'un fichier utf8 est valide :

$ isutf8 fichier && echo OK || echo "Not OK" 

Ne pas écraser un fichier de destination avant la fin de la commande :

# Version fonctionnelle de cat a b > a
$ cat a b | sponge a

Créer un script de type cron avec un lock sans effort :

$ lckdo -W 10 /var/lock/mylock /usr/local/bin/myscript

Éditer le contenu d'un pipe (très pratique pour le debug de script) :

$ commande1 | vipe | commande2

Éviter les envois de mail de rapport lorsqu'il n'y a rien à rapporter :

$ /usr/local/bin/rapport.pl | ifne mail -s "Synchro en retard" sysadmins@mynnet.net

Permettre (optionnelle ment) de passer des fichiers compressés en argument à un script (comme pour zless) :

# Recoder zless
$ zrun less $1

Éviter de parser le résultat de ifconfig ou de ip dans un script (nombreuses options, de sortie, lire le man) :

# Afficher le nombre d'octets reçus
$ ifdata -sib eth0

Passer le résultat d'une commande à plusieurs autres

# Attention si commande1 et commande2 produit du texte, rien ne garantit leur ordre
$ commande | pee "commande1" "commande2"

Comparer ligne par ligne deux fichiers avec des opérateurs plus évolués que comm :

$ combine fichier1 xor fichier2

Niveau : Star Star Empty Empty Empty
Résumé : man -H ; $- ; dd ; losetup ; bc ; APT::Install-Recommends=false ; /proc/net/ip_conntrack

Tester si on est dans un shell interactif (spécifique bash) :

$ if [[ "$-" == *i* ]]; then echo INTERACTIF; fi

Réduire le lecteur dvd au silence :

# copie sur le disque, attention au changement de media :-)
$ dd if=/dev/dvd of=/tmp/dvd && sudo rm /dev/dvd && sudo ln -s /tmp/dvd /dev/dvd

Réduire le lecteur dvd au silence (mieux):

# copie sur le disque puis loopback, attention au changement de media :-)
$ dd if=/dev/dvd of=/tmp/dvd
$ loop=$(sudo losetup-f)
$ sudo losetup $loop /tmp/dvd
$ sudo rm /dev/dvd && sudo ln -s $loop /dev/dvd

Conversion de base :

# hexadécimal -> decimal
$ echo "ibase=10; AC"|bc
# décimal -> hexadecimal
$ echo "obase=16; 100"|bc

Lecture des pages de man dans firefox :

$ man -Hfirefox ls
# si /etc/alternatives/www-browser (debian) ou $BROWSER pointent vers le bon navigateur
$ man -H ls

Ne pas installer les paquets recommandés pendant une installation (base debian, ubuntu ...) :

## apt-get install -o APT::Install-Recommends=false LePaquet
# Mieux
apt-get --no-install-recommends install LePaquet

Bloquer a fonction de routage d'un noyau < 2.6.12 :

while true; do cat /proc/net/ip_conntrack > /dev/null; done

Niveau : Star Star Empty Empty Empty
Résumé : perl

Perl fait beaucoup de choses, trop, tellement que certaines sont complètement inutiles

Il est possible de changer la numérotation des tableaux :

# le premier élément d'un tableau sera maintenant le numéro 42
$[=42;

Il est possible d'allouer de la mémoire inutilisée :

# alloue 64Mio de mémoire pour que perl puisse les utiliser quand il meurt a cause du manque de mémoire !!
# ce qui ne l'empêche pas de mourir bien sur
$^M=64<<20; 

Les sections BEGIN {} et END {} sont des blocs très utiles qui s'écrivent tels quel, mais il peuvent aussi être écrits comme des méthodes :

sub BEGIN {}

Perl disposes de modules en provenance du CPAN. Parmi ces modules on trouve les modules Acme, dont voici quelques exemples pour bien en comprendre l'utilité :

  • Acme::Anything qui permet de charger des modules qui n'existent pas
  • Acme::Error qui permet d'afficher toutes les erreurs en capitales.
  • Acme::Godot qui vous permet d'attendre Godot
  • Acme::EyeDrops pour convertir votre code perl en ascii art (fonctionnel en perl), très joli d'ailleurs
  • Acme::Code::Police supprime toute erreur de code qui n'utiliserait pas strict en supprimant le code.

Niveau : Star Star Empty Empty Empty
Résumé : .vimrc

Le retour du Jedi ! Les vacances sont finites, il est temps de de reprendre le dur cheminement dans le monde libre.

Après le vif succès du bashrc collaboratif, je vous propose de participer à un vimrc collaboratif. Le principe est le même, j'amorce le contenu d'un vimrc avec plein de petites choses utiles pour tous les jours, et vous complétez par des commentaires. Ceux-ci seront réintégrés avec votre nom dans l'article au fur et à mesure.

Attention, un guillemet double commence un commentaire :

" Plein de défauts bien pratiques (à garder en début de fichier)
set nocompatible

" Coloration syntaxique, indispensable pour ne pas se perdre dans les longs fichiers
syntax on

" Le complément du précédent, devine tout seul la couleur du fond (clair sur foncé ou le contraire)
set background&

"Détection du type de fichier pour l'indentation
if has("autocmd")
  filetype indent on
endif

" Récupération de la position du curseur entre 2 ouvertures de fichiers
" Parfois ce n'est pas ce qu'on veut ...
if has("autocmd")
  au BufReadPost * if line("'\"") > 0 && line("'\"") <= line("$")
    \| exe "normal g'\"" | endif
endif

" SI c'est pas déjà fait, affiche la position du curseur
set ruler

" Recherche en minuscule -> indépendante de la casse, une majuscule -> stricte
set smartcase

" Ne jamais respecter la casse (attention totalement indépendant du précédent mais de priorité plus faible)
set ignorecase

" Déplacer le curseur quand on écrit un (){}[] (attention il ne s'agit pas du highlight
"set showmatch

" Affiche le nombre de lignes sélectionnées en mode visuel ou la touche/commande qu'on vient de taper en mode commande
set showcmd

" Déplace le curseur au fur et a mesure qu'on tape une recherche, pas toujours pratique, j'ai abandonné
"set incsearch

" Utilise la souris pour les terminaux qui le peuvent (tous ?)
" pratique si on est habitué à coller sous la souris et pas sous le curseur, attention fonctionnement inhabituel
"set mouse=a

" A utiliser en live, paste désactive l'indentation automatique (entre autre) et nopaste le contraire
set nopaste

" Indiquer le nombre de modification lorsqu'il y en a plus de 0 suite à une commande
set report=0

" Met en évidence TOUS les résultats d'une recherche, A consommer avec modération
set hlsearch

" Crée des fichiers ~ un peu partout ...
set backup

" La ruse de sioux pour ne pas qu'ils soient partout (à vous de faire le mkdir)
" En général n'édite pas 2 fichiers de même noms fréquemment dans des répertoires différents, sinon évitez
" -> voir by eric plus bas

" Laisse les lignes déborder de l'écran si besoin
set nowrap

" En live pour quand vous écrivez anglais (le fr est à trouver dans les méandres du net)
"set spell


" Spécial développeurs
"
" Indispensable pour ne pas tout casser avec ce qui va suivre
set preserveindent
" indentation automatique
"set autoindent
" Largeur de l'autoindentation
set shiftwidth=4
" Arrondit la valeur de l'indentation
set shiftround
" Largeur du caractère tab
set tabstop=4
" Largeur de l'indentation de la touche tab
set softtabstop=4
" Remplace les tab par des expaces
"set expandtab

" by acieroid
" -----------
" Pour highlighter la ligne courante (pour mieux se repérer) en bleu :
set cursorline
highlight CursorLine ctermbg=blue

" Pour activer les numéros de lignes dans la marge :
set number

" by eric
" -----------
" Utilise shiftwidth à la place de tabstop en début de ligne (et backspace supprime d'un coup si ce sont des espaces)
set smarttab

" sauvegarder les fichier ~ dans ~/.vim/backup avec crréation du répertoire si celui-ci n'existe pas
if filewritable(expand("~/.vim/backup")) == 2
  set backupdir=$HOME/.vim/backup
else
  if has("unix") || has("win32unix")
    call system("mkdir $HOME/.vim/backup -p")
    set backupdir=$HOME/.vim/backup
  endif
endif

" donner des droits d'exécution si le fichier commence par #! et contient /bin/ dans son chemin
function ModeChange()
  if getline(1) =~ "^#!"
    if getline(1) =~ "/bin/"
      silent !chmod a+x <afile>
    endif
  endif
endfunction

au BufWritePost * call ModeChange()

" by anonyme
" -----------
" autoindent n'est spécifique à aucun langage et fonctionne en général moins bien
set noautoindent
filetype plugin indent on
filetype indent on

" by gnuk
" -----------
" On peut passer rapidement du mode paste au mode nopaste avec un raccourcis,
" builtin sur les versions récentes de vim >= 7, sinon il faudrait créer une fonction :
set pastetoggle=<F5>

" Toujours laisser des lignes visibles (içi 3) au dessus/en dessous du curseur quand on
" atteint le début ou la fin de l'écran :
set scrolloff=3

" Afficher en permanence la barre d'état (en plus de la barre de commande) :
set laststatus=2

" Format de la barre d'état (tronquée au début, fichier, flags,  :
set statusline=%<%f%m\ %r\ %h\ %w%=%l,%c\ %p%%

" Permettre l'utilisation de la touche backspace dans tous les cas :
set backspace=2

" Envoyer le curseur sur la ligne suivante/précédente après usage des flèches droite/gauche en bout de ligne :
set whichwrap=<,>,[,]

" Tenter de rester toujours sur la même colonne lors de changements de lignes :
set nostartofline

" Nombre de commandes maximale dans l'historique :
set history=50

" Afficher une liste lors de complétion de commandes/fichiers :
"set wildmode=list:full

" shebang automatique lors de l'ouverture nouveau
" d'un fichier *.py, *.sh (bash), modifier l'entête selon les besoins :
:autocmd BufNewFile *.sh,*.bash 0put =\"#!/bin/bash\<nl># -*- coding: UTF8 -*-\<nl>\<nl>\"|$
:autocmd BufNewFile *.py 0put=\"#!/usr/bin/env python\"|1put=\"# -*- coding: UTF8 -*-\<nl>\<nl>\"|$

A vous les studios ...

PS: Vous pouvez aussi taper ces commandes dans l'éditeur après un ':' et l'autocomplétion fonctionne !

Niveau : Star Star Star Empty Empty
Résumé : perl

Quelques trucs et astuces de perlistes en vrac. Pour des vrais astuces de pro régulières, n'hésitez pas à visiter le site des moines de perl.

Initialiser un tableau de chaînes sans avec une syntaxe légère, très lisible quand on n'a que des mots, le séparateur étant les caractères blancs, incluant le retour à la ligne :

@tableau = qw( mot1 mot2 mot3 );

Passer du mode script de quelques lignes au mode développement long. Cela vous oblige à déclarer et initialiser toutes vos variables entre autre :

use strict;

Le debug facile :

use Data::Dumper;
# variable peut être n'importe quoi, toutes les sous-sous parties sont écrites :
print Dumper($variable,\@variable);
print Dumper(\%variable);

L'aide en ligne facile, ça fait tout de suite classe dans un script (format) :

use Pod::Usage;
# imprime le contenu de SYNOPSIS et termine le programme avec un code d'erreur 1
pod2usage(1);
# attention, pod est chatouilleux sur les retours à la ligne avant et après les =

=head1 SYNOPSIS

commande  [-o|--option=<valeur>]

=cut

La page de manuel facile (pas seulement le SYNOPSIS comme précédemment) :

# où fichier.pl est le code précédent
$ pod2man fichier.pl > fichier.1
$ man ./fichier.1

Et le dernier pour la route, le parsing d'options facile, très classe, surtout en combinaison avec pod2usage (format) :

use Getopt::Long;
my $options = {
        option => 'defaut'
};
GetOptions( $options, qw(
        option|o=s
));