samedi 30 juillet 2011

OOo base: retour vers le futur

La version de libreoffice-base actuellement livrée avec Ubuntu 11.04 est cassée en ce sens que les barres d'outils nécessaires pour modifier un formulaire ne s'affichent pas.
Alors, une solution consiste à installer openoffice.org à la place de libreoffice.
Mais tant qu'à faire, plutôt que d'installer la version actuelle (3.3), autant installer la version précédente (3.2.1). En effet, un autre problème se pose pour ceux qui désirent accéder à PostgreSQL via le pilote sdbc: l'accès aux données se fait en lecture seule avec les versions d'openoffice.org et de libreoffice >= 3.3.
Choisissons sur cette page le fichier qui convient à son architecture (OOo_3.2.1_Linux_x86-64_install-deb_fr.tar.gz, si on est en 64 bits).
Après avoir téléchargé le fichier, ouvrons un (émulateur de) terminal, et rendons-nous à l'endroit du téléchargement pour procéder à l'extraction du tar.gz:
toto@rigel: ~$ cd Téléchargements/
toto@rigel: Téléchargements$ tar xzvf OOo_3.2.1_Linux_x86-64_install-deb_fr.tar.gz
L'extraction a créé différents dossiers. Nous devons nous y rendre pour procédons à l'installation:
toto@rigel: Téléchargements$ cd OOO320_m18_native_packed-1_fr.9502/DEBS
toto@rigel: DEBS$ sudo dpkg -i *.deb
Et pour finaliser:
toto@rigel: DEBS$ cd desktop-integration/
toto@rigel: desktop-integration$ sudo dpkg -i *.deb
Reste à régler le problème du pilote sdbc. Recherchons et téléchargeons le paquet debian openoffice.org-sdbc-postgresql_0.7.6+OOo3.2.0-4ubuntu1_amd64.deb (qui convient pour du 64 bits). Essayant d'installer ce paquet, on se heurte à des problèmes de dépendances. Plutôt que de forcer l'installation, il est préférable de procéder en douceur. Créons un dossier de travail et mettons-y  le fichier téléchargé:
toto@rigel: Téléchargements$ mkdir work
toto@rigel: Téléchargements$ mv openoffice.org-sdbc-postgresql_0.7.6+OOo3.2.0-4ubuntu1_amd64.deb work
toto@rigel: Téléchargements$ cd work
toto@rigel: work$
Un paquet debian est une archive "ar" (et non pas "tar").
Procédons à l'extraction:
toto@rigel: work$ ar -xv openoffice.org-sdbc-postgresql_0.7.6+OOo3.2.0-4ubuntu1_amd64.deb
x - debian-binary
x - control.tar.gz
x - data.tar.lzma
toto@rigel: work$
Ce qui nous intéresse c'est le tar.lzma:
toto@rigel: work$ tar -xv --lzma -f data.tar.lzma
./
./usr/
./usr/lib/
./usr/lib/openoffice/
./usr/lib/openoffice/share/
./usr/lib/openoffice/share/extension/
./usr/lib/openoffice/share/extension/install/
./usr/lib/openoffice/share/extension/install/postgresql-sdbc-0.7.6a.zip
./usr/share/
./usr/share/doc/
./usr/share/lintian/
./usr/share/lintian/overrides/
./usr/share/lintian/overrides/openoffice.org-sdbc-postgresql
./usr/share/bug/
./usr/share/bug/openoffice.org-sdbc-postgresql/
./usr/share/bug/openoffice.org-sdbc-postgresql/script
./usr/share/bug/openoffice.org-sdbc-postgresql/presubj
./usr/share/doc/openoffice.org-sdbc-postgresql
toto@rigel: work$
Déplaçons le fichier zip dans le répertoire de téléchargement:
toto@rigel: work$
toto@rigel: work$ mv usr/lib/openoffice/share/extension/install/postgresql-sdbc-0.7.6a.zip ../
Nous aurons ainsi plus de facilité pour ajouter l'extension dans openoffice via "Outils-> Gestionnaire des extensions"
Nous pouvons maintenant détruire le répertoire de travail work.

mercredi 20 juillet 2011

Pilote postgresql sdbc 64 bits

Dans le billet Connecter openoffice à PostgreSQL, nous avons donné un lien permettant de télécharger le pilote sdbc.
Hélas, le pilote ainsi obtenu ne fonctionne pas si on est en 64 bits.
Certaines distributions fournissent un paquet 64 bits qui délivre le pilote en question. Par exemple chez Ubuntu, il s'agit du paquet libreoffice-sdbc-postgresql. Pour d'autres distributions ce paquet n'existe pas.
Voici comment contourner le problème. Ceci a été testé et fonctionne dans le cas de Fedora 15.
Tout d'abord, rechercher et télécharger, par exemple, le paquet libreoffice-base-drivers-postgresql-3.3.1.2-1.2.3.x86_64.rpm. Il s'agit d'un paquet openSuse.
Ensuite, dans un terminal, se rendre là où le paquet est téléchargé:
$ cd ~/Téléchargement 
$ rpm2cpio libreoffice-base-drivers-postgresql-3.3.1.2-1.2.3.x86_64.rpm | cpio -ivd
./usr/lib64/libreoffice/share/extensions/postgresql-sdbc-0.7.6b
./usr/lib64/libreoffice/share/extensions/postgresql-sdbc-0.7.6b/META-INF
./usr/lib64/libreoffice/share/extensions/postgresql-sdbc-0.7.6b/META-INF/manifest.xml
./usr/lib64/libreoffice/share/extensions/postgresql-sdbc-0.7.6b/description.xml
./usr/lib64/libreoffice/share/extensions/postgresql-sdbc-0.7.6b/postgresql-sdbc-impl.uno.so
./usr/lib64/libreoffice/share/extensions/postgresql-sdbc-0.7.6b/postgresql-sdbc.uno.so
./usr/lib64/libreoffice/share/extensions/postgresql-sdbc-0.7.6b/postgresql-sdbc.unorc
./usr/lib64/libreoffice/share/extensions/postgresql-sdbc-0.7.6b/postgresql.xcu
1779 blocs
$

La commande rpm2cpio convertit le paquet RPM en archive cpio, archive qui est transmise à la commande cpio pour extraction. La commande cpio a créé dans "Téléchargement" toute une série de répertoires. Nous allons en premier ramener le répertoire "postgresql-sdbc-0.7.6b" dans "Téléchargement", puis créer le fichier zip adéquat:
$ mv usr/lib64/libreoffice/share/extensions/postgresql-sdbc-0.7.6b .
$ zip -r postgresql-sdbc-0.7.6b.zip postgresql-sdbc-0.7.6b
adding: postgresql-sdbc-0.7.6b/ (stored 0%)
adding: postgresql-sdbc-0.7.6b/postgresql-sdbc.unorc (stored 0%)
adding: postgresql-sdbc-0.7.6b/description.xml (deflated 52%)
adding: postgresql-sdbc-0.7.6b/META-INF/ (stored 0%)
adding: postgresql-sdbc-0.7.6b/META-INF/manifest.xml (deflated 62%)
adding: postgresql-sdbc-0.7.6b/postgresql-sdbc-impl.uno.so (deflated 68%)
adding: postgresql-sdbc-0.7.6b/postgresql.xcu (deflated 57%)
adding: postgresql-sdbc-0.7.6b/postgresql-sdbc.uno.so (deflated 71%)
$

Pour terminer, il suffit de procéder comme indiqué dans le billet Connecter openoffice à PostgreSQL:
$ cd $(dirname $(which soffice));cd $(ls -l soffice | sed -r 's/^.*>.(.*)soffice$/\1/')
$ unopkg add ~/Téléchargement/postgresql-sdbc-0.7.6b.zip
$
Il nous est bien sûr loisible de plutôt procéder à l'ajout l'extension via le Gestionnaire des extensions (menu Outils) de Libreoffice.

samedi 2 juillet 2011

Vous avez dit sourcer?

Pour mener à bien une compilation, nous avons besoin de définir toute une série de variables d'environnement. Les définitions de ces variables se trouvent par exemple dans un fichier nommé def-var:

export QTDIR=`kde4-config --qt-prefix`
export KDEDIR=`kde4-config --prefix`
export KDEDIRS=$KDEDIR
export KDE_BUILD=$KDEDIR
export DBUSDIR=$KDEDIR
export LD_LIBRARY_PATH=$QTDIR/lib:$KDEDIR/lib:$LD_LIBRARY_PATH
export PKG_CONFIG_PATH=$DBUSDIR/lib/pkgconfig:/usr/lib/pkgconfig
export PATH=$QTDIR/bin:$KDEDIR/bin:$PATH

Si nous exécutons def-var dans un terminal et que nous regardons ensuite ce qu'il en est au niveau des variables d'environnement existant dans le terminal, rien n'est changé.
Alors comment procéder? Taper toutes ces commandes?
Non, bien sûr: il existe une autre méthode.

Bon, reprenons en partant d'un fichier un peu plus ludique: le fichier bjr:

echo $PPID-$$
echo Saisis un nom $moi
read moi
cat << FIN
Toujours saluer le directeur:
Bonjour $moi
FIN

situé dans /home/toto/test.
Ce fichier contient toute une série de commandes.
Elles sont là, déjà écrites dans le fichier! Alors pourquoi les retaper?
Il suffit d'indiquer à bash que bjr constitue une source de commandes:


L'output de la commande echo est affiché en premier. Puis la commande "read moi" provoque l'affichage du curseur: le système est en attente de ce que nous allons taper au clavier afin de le mettre dans la variable moi:


Terminons la saisie par un appui sur ENTER:


Tapons effectivement à l'écran la première commande de bjr:


Le résultat est le même:  2849 est le pid du shell bash dans lequel nous sommes et 2838 celui de son processus parent (par exemple konsole ou gnome-terminal)
Lorsque bjr est sourcé, tout se passe comme si les commandes qu'il contient étaient tapées à l'écran. Ainsi la variable moi est maintenant définie dans le shell bash (pid 2849) avec la valeur "Ahuri".

Le mot "source" étant très long (et donc fatiguant à taper), il est le plus souvent remplacé par un point ("."):


Nous constatons que la variable moi est bel et bien définie (elle contient le mot "Ahuri") avant même l'exécution de la commande read

Et si nous exécutions bjr en tapant tous simplement son nom, comme pour n'importe quelle commande?
Problème:

C'est normal, bjr n'est pas trouvé car /home/toto/test ne figure dans la variable d'environnement PATH qui contient l'ensemble des répertoires où le système recherche les commandes.
Par curiosité, examinons le contenu de PATH:


/home/toto/test n'y figure évidemment pas, mais bien à toutes fins utiles /home/toto/bin.
Ainsi nous pourrions créer le lien symbolique qui convient.
ln -s ../test/bjr ../bin
Mais la réponse classique au problème consiste à indiquer au système où se trouve exactement la commande à exécuter en tapant:
/home/toto/test/bjr
ou plus court:
./bjr

En fait c'est la même chose:


Nous affichons d'abord les inodes des différents fichiers du dossier (y compris les fichiers cachés). En faisant une recherche sur l'inode 1717900 nous voyons que le fichier "." n'est autre que le dossier dans lequel on se trouve (/home/toto/test).
Ceci est bien connu et a déjà été expliqué dans un autre billet.

Le point (.) peut donc être mangé à plusieurs sauces.

Résumons:
. bjr : le point remplace la commande "source". bjr sera sourcé.
./bjr : le point remplace (ici) /home/toto/test. bjr sera exécuté.

Procédons à l'exécution (!):


Nouveau problème! Et oui: personne n'a le droit d'exécuter ce fichier, même pas le root.
Avant de procéder il faut d'abord donner le droit d'exécution sur bjr (avec la commande chmod +x bjr):


Intéressons nous à ce que vaut maintenant la variable moi dans le shell bash de base:


C'est encore la valeur résultant du "read" lorsque bjr a été sourcé pour la deuxième fois.

Constatations:
  • Les différentes commandes du script bjr, s'exécutent au sein d'un sous-shell (pid 2946) dérivé du shell bash principal (pid 2849).
  • Dans ce sous-shell, la variable moi n'est au départ pas définie (elle prend ensuite la valeur Jules).
  • L'exécution de bjr ne modifie pas la valeur de la variable moi dans le shell bash principal (contrairement à ce qui se passe lorsque bjr est sourcé).
    La variable moi n'est pas définie au départ dans le sous-shell où bjr tourne car ce n'est pas une variable d'environnement. Et quand bien même l'aurait-elle été (un petit export moi tapé à l'écran et hop!), cela aurait changé quoi ?
    • Elle aurait alors été définie d'emblée dans le sous-shell 2946 et la ligne 2 du résultat de l'exécution de bjr aurait été:  Saisis un nom Patate
    • Sa valeur serait comme avant restée inchangée au niveau shell maître
      Un changement de valeur dans un sous-shell ne se répercute pas dans le shell parent.

      Afin de consolider toutes ces notions, raisonnons maintenant sur un cas un peu plus compliqué, metttant en scène le fichier lbjr:

      echo $PPID-$$
      echo Bonjour $moi
      . defvar
      ./bjr
      echo Il répondra: appelez-moi $moi

      et le fichier defvar

      echo $PPID-$$
      moi=Big\ Boss

      (Remarquons le caractère d'échappement "\" qui enlève au blanc qui suit le mot "Big" son rôle de séparateur)

      Exécutons lbjr. Mais comme nous n'avons pas le courage de le rendre exécutable, procédons en utilisant la commande bash:


      Analysons le résultat:
      • ligne 1: lbjr s'exécute dans un sous-shell (pid 2949)
      • ligne 2: dans ce sous-shell la variable moi n'est pas définie
      • ligne 3: defvar est sourcé au niveau du sous-shell et la commande echo de defvar s'exécute bien dans ce sous-shell
      • ligne 4: bjr s'exécute dans un sous-sous-shell (pid 2950)
      • dernière ligne: bjr est terminé, on est retombé dans le sous-shell 2949 et la variable moi est est maintenant définie dans ce sous-shell car defvar y a été sourcé.
      Si defvar n'avait pas été sourcé, mais exécuté (commande ./defvar au lieu de . defvar), la variable moi serait restée non définie dans le shell pid 2949.

      Nous n'avons pas eu le courage de rendre lbjr exécutable, mais bash c'est quand même très long à écrire: pourquoi ne pas utiliser sh?
      Après tout sh est maintenant le plus souvent un simple lien vers bash:


      Et pourtant:


      Et oui : le comportement de bash change suivant la façon dont il est invoqué.
      Le mieux est d'indiquer précisément l'endroit où se trouve le fichier à sourcer, ce qui évite ce genre d'erreur.

      Pour en revenir avec le problème qui a motivé ce billet, la solution est bien évidemment de sourcer def-var dans le shell bash de travail. Les variables d'environnement, nouvelles où modifiées, seront ainsi présentes pour tous les processus fils

      mercredi 8 juin 2011

      Postgresql: localisation

      En guise de préambule, notons que le plus souvent aucun problème de localisation ne se pose avec postgresql, mais parfois quelques surprises se trouvent au rendez-vous...

      Suivant ce qui est expliqué dans le billet PostgreSQL (initiation), nous procédons, après l'installation du paquet postgresql, à l'initiation de la base de données:


      Tiens cette fois les messages sont en anglais. Pourtant notre système (Fedora 15) semble bien francisé.
      Un doute affreux s'insinue. Vérifions: après être devenu postgres, affichons la liste des bases de données existantes:


      Enfer et damnation!
      Mais qu'à cela ne tienne: man createdb nous apprend que l'on peut choisir la localisation avec l'option --locale.
      Bon, continuons avec la création de l'utilisateur toto. Lançant la commande createuser  sans options, nous sommes interrogés sur nos intentions:


      Ensuite après être devenu toto, nous procédons à la création de notre base de donnée à l'aide de la commande createdb et de l'option --locale.
      Notre base de données s'appellera bd01:


      Mais à quoi sert l'option --locale alors?
      Manifestement, quelque chose nous échappe.
      (EDIT: voir ici)
      Mais tant pis: aux grands maux, les grands remèdes.
      Cherchons où se trouve le database cluster?


      Arrêtons le service postgresql et supprimons le cluster en question:


      Nous pouvons maintenant initialiser le cluster à notre guise en utilisant la commande initdb, mais attention initdb ne peut pas être lancé par le root. On va l'exécuter en tant que postgres:

      bash-4.2$ initdb -A ident -D /var/lib/pgsql/data --locale=fr_FR.utf8
      Les fichiers de ce cluster appartiendront à l'utilisateur « postgres ».
      Le processus serveur doit également lui appartenir.

      Le cluster sera initialisé avec la locale fr_FR.utf8.
      L'encodage par défaut des bases de données a été configuré en conséquence
      avec UTF8.
      La configuration de la recherche plein texte a été initialisée à « french ».

      correction des droits sur le répertoire existant /var/lib/pgsql/data... ok
      création des sous-répertoires... ok
      sélection de la valeur par défaut de max_connections... 100
      sélection de la valeur par défaut pour shared_buffers... 28MB
      création des fichiers de configuration... ok
      création de la base de données template1 dans /var/lib/pgsql/data/base/1... ok
      initialisation de pg_authid... ok
      initialisation des dépendances... ok
      création des vues système... ok
      chargement de la description des objets système... ok
      création des conversions... ok
      création des dictionnaires... ok
      initialisation des droits sur les objets internes... ok
      création du schéma d'informations... ok
      chargement du langage PL/pgSQL... ok
      lancement du vacuum sur la base de données template1... ok
      copie de template1 vers template0... ok
      copie de template1 vers postgres... ok

      Succès. Vous pouvez maintenant lancer le serveur de bases de données par :

          postgres -D /var/lib/pgsql/data
      ou
          pg_ctl -D /var/lib/pgsql/data -l journal_applicatif start

      Les commandes indiquées, postgres et pg_ctl, ne peuvent pas être exécutées par le root (tout comme initdb):
      On a le choix:
      • soit utiliser une des commandes postgres ou pg_ctl en tant qu'utilisateur postgres
      • soit la commande service postgresql start en tant que root.
      Dans ce blog, nous n'avons pas encore présenté les commandes postgres ou pg_ctl. Voici l'occasion d'en dire un peu plus à ce sujet. Pour peu que la variable d'environnement PGDATA soit définie de manière adéquate (par exemple en ayant ajouté en temps utile export PGDATA=/var/lib/pgsql/data au fichier /etc/bashrc), l'option -D est inutile.

      La commande postgres tourne en avant plan, comme ceci:


      La commande pg_ctl elle, tourne en arrière plan et les lignes de log qui étaient affichées à l'écran avec la commande postgres sont dirigées suite à l'emploi de l'option -l vers le fichier désigné, à savoir: journal_applicatif.

      Dans le système d'exploitation que nous utilisons actuellement (Fedora 15), les informations de log sont capturées et dirigées vers un fichier du répertoire /var/lib/pgsql/data/pg_log. On n'a donc aucun intérêt à utiliser la commande postgres ou l'option -l avec pg_ctl (puisque journal_applicatif resterait vide). Nous allons démarrer le serveur avec la commande pg_ctl start tout simplement:
      Bien sûr, l'utilisateur toto a disparu: il doit de nouveau être créé par postgres:


      Cette fois createuser nous parle en français (c'est bon signe).
      Ensuite dans une fenêtre où nous sommes toto:


      C'est merveilleux.

      Arrêtons le serveur:


      Nous voudrions maintenant procéder en démarrant le serveur en tant que root.
      Ça ne fonctionne pas!


      Étonnant puisque avec l'autre méthode le serveur démarre!
      C'est SELinux qui fait des siennes:


      SELinux is preventing /usr/bin/postgres from getattr access on the fichier /var/lib/pgsql/data/postgresql.conf.


      Il faut restaurer le contexte de sécurité:


      [root@rigel ~]# /sbin/restorecon -R /var/lib/pgsql/
      /sbin/restorecon set context /var/lib/pgsql/data/postgresql.conf->system_u:object_r:postgresql_t:s0 failed:'Permission denied'

      Lorsque tout fonctionne bien, la commande /sbin/restorecon (dans le contexte où elle a été utilisée) ne fournit aucun retour. Habituellement c'est le cas, mais pas cette fois: un problème se pose pour le fichier postgresql.conf. La commande semanage devrait pouvoir le résoudre:



      [root@rigel ~]# semanage fcontext -a -t postgresql_db_t /var/lib/pgsql/data/postgresql.conf
      [root@rigel ~]# /sbin/restorecon -v  /var/lib/pgsql/data/postgresql.conf
      /sbin/restorecon reset /var/lib/pgsql/data/postgresql.conf context unconfined_u:object_r:var_lib_t:s0->system_u:object_r:postgresql_db_t:s0 


      Tout semble en ordre maintenant. vérifions-le en affichant le contexte de sécurité avant de démarrer le serveur:


      Ce qui suit est hors-sujet, mais comme nous avons maintenant présenté la commande pg_ctl, la question peut être posée:
      quelle est la meilleur façon d'arrêter le serveur?
      Examinons le fichier log.
      Avec pg_ctl stop, ça donne ceci:




      Avec service postgresql stop (ou lorsqu'on arrête l'ordinateur sur lequel tourne le serveur):



      La réponse semble aller de soi.
      Presque tout ce qui est expliqué dans ce billet peut s'appliquer à quelques détails près à la plupart des distributions. Avec cette évidence: SELinux quand il n'est pas installé ou quand il n'est pas actif ne pose évidemment aucun problème.
      En ce qui concerne Ubuntu (11.04), c'est un peu plus compliqué. Les données ne se trouvent pas à l'emplacement habituel, mais on trouve sans difficulté où elles se trouvent:

      root@rigel:~# ps -U postgres -o command | awk 'NR==2'
      /usr/lib/postgresql/8.4/bin/postgres -D /var/lib/postgresql/8.4/main -c config_file=/etc/postgresql/8.4/main/postgresql.conf
      root@rigel:~#


      Par contre lorsqu'on veut exécuter initdb, la commande est introuvable.
      Il convient de créer les liens suivant:


      root@rigel:~# cd /usr/bin
      root@rigel:/usr/bin# ln -s ../share/postgresql-common/pg_wrapper initdb
      root@rigel:/usr/bin# ln -s ../share/postgresql-common/pg_wrapper postgres
      root@rigel:/usr/bin# ln -s ../share/postgresql-common/pg_wrapper pg_ctl


      Démarrer le serveur avec postgres ou pg_ctl ne pose aucun problème, mais l'utilisation de service postgresql start conduit à un échec suite à un problème de certificats manquants. Il s'agit donc de recréer les liens qui ont disparu lors de la suppression de /var/lib/postgresql/8.4/main:


      root@rigel:~# cd /var/lib/postgresql/8.4/main/
      root@rigel:/var/lib/postgresql/8.4/main# ln -s /etc/ssl/certs/ssl-cert-snakeoil.pem server.crt
      root@rigel:/var/lib/postgresql/8.4/main# ln -s /etc/ssl/private/ssl-cert-snakeoil.key server.key


      mardi 30 novembre 2010

      Espace disque

      Météo.
      Nous créons le dossier test et nous y plaçons le fichier "météo" dont voici le contenu:
      Belle journée ensoleillée.
      Températures de 24 à 28 degrés.
      Vent modéré.
      Examinons maintenant le contenu du dossier avec la commande ls et les options:
      g: pour un affichage au format long mais sans le propriétaire
      o: idem sans le groupe
      a: pour afficher les fichiers cachés
      i: pour afficher le numéro d'inode
      s: pour afficher la taille en blocs
      toto@rigel:~$ ls -goais test
      total 12
      1308818 4 drwxr-xr-x  2 4096 2010-11-26 10:10 .
      1308748 4 drwxr-xr-x 39 4096 2010-11-26 10:04 ..
       442198 4 -rw-r--r--  1   79 2010-11-26 10:10 météo
      La première colonne contient les identifiants numériques (numéro d'inode) des fichiers. Ensuite vient une colonne avec l'espace disque occupé par chaque fichier, en blocs de 1024 octets. Ces blocs n'ont aucun rapport avec les blocs du système de fichier (ext3, taille 4096 octets), ni avec les blocs du disque (taille 512 octets). A gauche des dates, on trouve une colonne avec des tailles en octets: 79 pour le fichier météo. Pour ceux qui veulent compter, ne pas oublier les caractères de contrôle "fin de ligne". Ne pas oublier, aussi que les caractères accentués comptent double (Nous sommes en UTF-8).
      Les deux premières lignes de la liste se rapportent à des dossiers comme l'indique le premier caractère de la colonne 3, c'est-à-dire d.
      Quels sont ces dossiers?
      La commande find permet de faire une recherche sur les identifiants numériques:
      toto@rigel:~$ find ~/ -inum 1308818 ; find ~/ -inum 1308748
      /home/toto/test
      /home/toto/
      Le premier fichier, "." n'est rien d'autre que le dossier test lui-même, tandis que le deuxième fichier, ".." est le dossier parent. Ce sont des résultats bien connus.

      Ce n'est pas mon frère, c'est moi.
      Procédons à quelques manipulations avant de relancer notre commande ls:
      toto@rigel:~$ cd test
      toto@rigel:~/test$ ln météo prévisions ; cp météo le_temps
      toto@rigel:~/test$ ls -goais
      total 20
      1308818 4 drwxr-xr-x  2 4096 2010-11-26 12:36 .
      1308748 4 drwxr-xr-x 39 4096 2010-11-26 10:04 ..
       442199 4 -rw-r--r--  1   79 2010-11-26 12:36 le_temps
       442198 4 -rw-r--r--  2   79 2010-11-26 10:10 météo
       442198 4 -rw-r--r--  2   79 2010-11-26 10:10 prévisions
      Nous avons maintenant semble-t-il, 3 fichiers identiques de 79 octets.
      Mais attention, les apparences sont trompeuses. En effet l'identifiant 442198 est répété. Donc nous avons dans le répertoire, deux entrées, deux noms différents (météo et prévisions) pour le même fichier (ce qui est indiqué par le chiffre 2 qui précède la taille en octets).
      Vérifions cela:
      toto@rigel:~/test$ echo 'Bonne soirée' >> prévisions
      toto@rigel:~/test$ ls -goais
      total 20
      1308818 4 drwxr-xr-x  2 4096 2010-11-26 12:36 .
      1308748 4 drwxr-xr-x 39 4096 2010-11-26 10:04 ..
       442199 4 -rw-r--r--  1   79 2010-11-26 12:36 le_temps
       442198 4 -rw-r--r--  2   93 2010-11-26 12:50 météo
       442198 4 -rw-r--r--  2   93 2010-11-26 12:50 prévisions
      La taille de météo et de prévisions passe à 93, ce qui montre bien qu'il s'agit de deux noms portés par un même fichier. Le lien existant entre météo et prévisions est appelé un lien en dur.
      Mais attendez, cela implique que le total repris en ligne 1 de l'output est faux, ou en tout cas qu'il ne correspond pas au nombre de blocs (de 1 K) occupés par les fichiers du dossier, puisque le fichier 442198 est compté deux fois.
      Pour un total correct, il faut procéder avec la commande du. Utilisons l'option -a pour que les fichiers comptabilisés apparaissent dans l'output:
      toto@rigel:~$ du -a test
      4       test/météo
      4       test/le_temps
      12      test
      Le chiffre 12 correspond au volume occupé par le fichier 442198 (météo), le fichier 442199 (le_temps) et le fichier 1308818 (le dossier test lui-même). L'entrée "prévisions" est ignorée. Le fichier 1308748, qui correspond au répertoire parent n'est pas repris. Deux entrées en moins (celles qui ne sont pas surlignées en saumon), à 4 K l'entrée: voilà qui explique pourquoi le total passe de 20 K à 12 K. Quant au fichier 1308748 (répertoire parent), du en tiendra compte uniquement pour le calcul du volume occupé par /home/toto ou par tout autre répertoire supérieur.

      Pour vivre heureux, vivons cachés.
      Effectuons encore quelques manipulations avant d'exécuter de nouveau la commande ls (avec l'option supplémentaire -R pour la récursivité):
      toto@rigel:~/test$ mkdir test.d1 test.d2
      toto@rigel:~/test$ mv prévisions test.d1 ; mv météo test.d2
      toto@rigel:~/test$ ls -Rgoais ~/test
      /home/toto/test:
      total 20
      1308818 4 drwxr-xr-x  4 4096 2010-11-27 11:42 .
      1308748 4 drwxr-xr-x 39 4096 2010-11-26 10:04 ..
       442199 4 -rw-r--r--  1   79 2010-11-26 12:36 le_temps
      1309068 4 drwxr-xr-x  2 4096 2010-11-27 11:42 test.d1
      1309591 4 drwxr-xr-x  2 4096 2010-11-27 11:42 test.d2

      /home/toto/test/test.d1:
      total 12
      1309068 4 drwxr-xr-x 2 4096 2010-11-27 11:42 .
      1308818 4 drwxr-xr-x 4 4096 2010-11-27 11:42 ..
       442198 4 -rw-r--r-- 2   93 2010-11-26 12:50 prévisions

      /home/toto/test/test.d2:
      total 12
      1309591 4 drwxr-xr-x 2 4096 2010-11-27 11:42 .
      1308818 4 drwxr-xr-x 4 4096 2010-11-27 11:42 ..
       442198 4 -rw-r--r-- 2   93 2010-11-26 12:50 météo
      Nous avons explicitement avec la commande "ln météo prévisions", créé un lien en dur. Mais de tels liens sont naturellement présents dans le système. Ainsi pour le fichier 1308818, le nombre 4 - en rouge, colonne 4 - indique qu'il lui correspond 4 entrées, dont 3 figurent dans l'output ci-dessous (il manque l'entrée dans /home/toto). Le fichier 1308818 contribue donc à chacun des 3 totaux.
      Que donne la commande du?
      toto@rigel:~/test$ du -a ~/test
      4       /home/toto/test/test.d1/prévisions
      8       /home/toto/test/test.d1
      4       /home/toto/test/le_temps
      4       /home/toto/test/test.d2
      20      /home/toto/test
      Remarquons en premier que si le total /home/toto/test est le même dans les deux cas (20) il s'agit d'un hasard: vu l'existence de sous-dossiers (non-vides), les deux nombres ont une signification différente. D'un côté  (commande ls), il s'agit du volume occupé par les fichiers qui ont une entrée dans le répertoire test et de l'autre (commande du), il s'agit du volume occupé par le dossier test et tout ce qu'il contient. Le fichier 1308748 (/home/toto) est bien comptabilisé par ls, mais pas par du (comme précédemment). Pour le fichier 442198 (prévisions), il contribue au total calculé par du, mais pas au total 20 de ls puisqu'il n'y a plus d'entrée pour ce fichier au niveau du répertoire test. Il suffirait que 442198 occupe plus de 4 K pour que les deux totaux ne soient plus égaux.
      Logiquement, du, contrairement à ls, ne tient pas compte du fichier 1308818 (/home/toto/test) pour le calcul du volume occupé par test.d1 et test.d2 (il en tient compte pour le volume occupé par test). Comme précédemment, nous avons surligné (en saumon) les items de l'output de ls dont la commande du tient compte.

      C'est trop injuste!
      Nous constatons que cette fois "météo" est ignoré par du au profit de "prévisions". Évidemment, il y a là un certain arbitraire. Pourquoi compter 8 K pour test.d1, 4 K pour test.d2 et non pas le contraire? D'ailleurs, si on a:
      toto@rigel:~/test$ du -ac test.d1 test.d2
      4       test.d1/prévisions
      8       test.d1
      4       test.d2
      12      total
      on a aussi:
      toto@rigel:~/test$ du -ac test.d2 test.d1
      4       test.d2/météo
      8       test.d2
      4       test.d1
      12      total
      Mais le principal est que le total des blocs occupés (affiché grâce à l'option -c) soit le bon. Attention, pour obtenir 12, il ne faut pas tenir compte des 4 K du fichier prévisions (météo) puisque ceux-ci sont inclus dans  les 8 K du dossier test-d1 (test-d2).
      Donc si on pouvait avoir l'output sans les fichiers, ce serait cool. Et bien il suffit de supprimer l'option -a:
      toto@rigel:~/test$ du -c test.d1 test.d2
      8       test.d1
      4       test.d2
      12      total
      toto@rigel:~/test$ du -c test.d2 test.d1
      8       test.d2
      4       test.d1
      12      total
      Mais avec la commande du ~/test, on a un problème:
      toto@rigel:~/test$ du ~/test
      8       /home/toto/test/test.d1
      4       /home/toto/test/test.d2
      20      /home/toto/test
      Le fichier le_temps a disparu, alors pour expliquer le 20 final...
      Comment procéder pour afficher le_temps sans pour autant faire réapparaitre prévisions, c'est-à-dire sans afficher le détail de test.d1 et test.d2 ?
      La solution se trouve dans l'emploi de l'option --max-depth:
      toto@rigel:~/test$ du ~/test -a --max-depth=1
      8       /home/toto/test/test.d1
      4       /home/toto/test/le_temps
      4       /home/toto/test/test.d2
      20      /home/toto/test

      Creuser, toujours creuser!
      L'option --max-depth=1 n'empêche pas du d'explorer l'arborescence plus en profondeur.
      Ainsi, après avoir procédé comme ci-dessous,
      toto@rigel:~/test$ mkdir test.d1/test.d3
      toto@rigel:~/test$ echo salut > test.d1/test.d3/salut
      toto@rigel:~/test$ echo hello > test.d1/test.d3/hello
      ce qui a ajouté test.d3 à l'arborescence:
      .
      ├── le_temps
      ├── test.d1
      │   ├── prévisions
      │   └── test.d3
      │       ├── hello
      │       └── salut
      └── test.d2
          └── météo
      nous constatons que l'output de la commande du, même avec --max-depth=1, est modifié en conséquence
      toto@rigel:~/test$ du ~/test -a --max-depth=1
      20      /home/toto/test/test.d1
      4       /home/toto/test/le_temps
      4       /home/toto/test/test.d2
      32      /home/toto/test
      On peut utiliser l'option -S. De la sorte, le volume figurant devant chaque nom de dossier se rapportera seulement au volume de ce dossier et aux fichiers qu'il contient: le volume devant test.d1 retrouvera son ancienne valeur (celle d'avant la création de test.d3). Par contre, le total qui peut être obtenu en ajoutant l'option c se rapportera à toute l'arborescence:
      toto@rigel:~/test$ du ~/test -acS --max-depth=1
      8       /home/toto/test/test.d1
      4       /home/toto/test/le_temps
      4       /home/toto/test/test.d2
      8       /home/toto/test
      32      total
      Si seul le total nous intéresse et en aucune façon une quelconque ventilation, il suffit d'utiliser l'option s:
      toto@rigel:~$ du -s ~/test
      32      /home/toto/test

      Quelle belle partition!
      Parmi les options de la commande du, on peut encore citer:
      -h pour afficher les volumes de manière facilement lisible
      -x pour rester dans le même système de fichiers.
      Exemple:
      root@rigel:~# du -hx --max-depth=1 /
      3,4G    /usr
      76K     /tmp
      8,0K    /home
      15M     /etc
      4,0K    /srv
      2,4G    /var
      0       /sys
      12K     /mnt
      275M    /opt
      6,6M    /bin
      255M    /lib
      8,0K    /media
      45M     /boot
      4,0K    /cdrom
      4,0K    /selinux
      7,6M    /sbin
      0       /dev
      0       /proc
      16K     /lost+found
      628K    /root
      6,3G    /
      La commande demande un certain temps pour s'exécuter. Rappelons que l'option --max-depth=1 ne limite nullement la profondeur du scan.
      Le volume de 8 K qui apparait devant /home montre bien que la partition montée en ce point n'a pas été explorée, et ce grâce à l'option -x.
      En ce qui concerne le total de la partition, un résultat peut être obtenu beaucoup plus rapidement avec la commande df:
      toto@rigel:~$ df -h /
      Sys. de fich.       Taille  Uti. Disp. Uti% Monté sur
      /dev/sdc1              11G  6,5G  3,6G  65% /
      df n'effectue aucun scan et tire directement ses informations du superbloc. Le montant obtenu n'est pas le même (6,5 G au lieu de 6,3 G). Pour df, il s'agit de l'espace occupé par le système de fichier et non de l'espace occupé par l'ensemble des fichiers. Et pour un système de fichier qui vient d'être créé, l'espace disponible n'est déjà plus égal à la taille.

      mardi 9 novembre 2010

      Les secrets de cat

      La commande cat copie vers la sortie standard le contenu du ou des fichiers indiqués sur la ligne de commande. Une simple redirection permet donc d'obtenir un fichier qui est la concaténation de plusieurs fichiers:

      toto@rigel:~/test$ cat garçons
      Toto
      Riri
      toto@rigel:~/test$ cat filles
      Tata
      Titine
      toto@rigel:~/test$ cat garçons filles > toutlemonde
      toto@rigel:~/test$ cat toutlemonde
      Toto
      Riri
      Tata
      Titine
      toto@rigel:~/test$

      C'est la finalité première de cat comme d'ailleurs annoncé au début de la page man:

      cat - concatenate files and print on the standard output

      Si aucun fichier n'est indiqué sur la ligne de commande, cat copie alors l'entrée standard vers la sortie standard:

      cat est en attente de ce que nous allons saisir au clavier (entrée standard) pour l'envoyer vers la sortie standard.
      Nous saisissons "hello"


      et tapons sur Enter pour envoyer le texte saisi vers cat:

      A l'écran figure ce que nous avons tapé au clavier, mais aussi ce qui a été renvoyé par cat via stdout (c'est évidement le même texte). cat continue à attendre la suite.
      Nous interrompons le flux d'entrée par appui sur CTRL-D.
      On peut s'amuser de la même façon avec tr par exemple:



      Seul un appui sur Enter sépare les deux dernières copies d'écran.
      Ce genre de manipulation est d'une utilité toute relative sauf si nous redirigeons stdout nous donnant ainsi la possibilité de créer un petit fichier texte:

      Cette fois évidemment les lignes n'apparaissent pas en double puisque l'output se fait vers le fichier salut. Comme précédemment, indiquons à cat avec CTRL-D qu'il ne doit plus rien attendre et puis vérifions (avec cat toujours) que le fichier salut contient bien ce qu'il est censé contenir.


      On peut intercaler la lecture de stdin entre la lecture de plusieurs fichiers en utilisant le signe "-":


      cat a lu le premier fichier, envoyé son contenu dans toutlemonde et est en attente de la suite qui doit venir de stdin. Saisissons "++++++", puis appuyons sur Enter:


      "++++++" se trouve déjà dans toutlemonde. Il reste à appuyer sur CTRL-D pour terminer:


      Attention, il s'agit de terminer proprement et non pas en utilisant CTRL-C, faute de quoi cat ne lira pas le second fichier.

      Considérons maintenant cette commande:


      Aucun nom de fichier n'est indiqué, donc cat devrait lire l'entrée standard. Mais l'instruction de redirection << FIN signifie à bash que ce qui suit, donc ici ce qui sera écrit à l'écran, constituera le flux d'entrée et ce jusqu'au mot FIN. cat va donc lire non pas l'entrée standard, mais le contenu de l'écran jusqu'à la rencontre du délimiteur FIN:




      Un simple appui sur Enter sépare ces deux copies d'écran.
      Le texte

      hello
      ola
      hi

      est ce qui s'appelle un here document.

      L'emploi de here documents est surtout utile dans les scripts: il permet d'éviter la multiplication des commandes echo.
      Soit le script courses:

      #!/bin/bash

      echo
      echo Bonjour $USER

      cat  << COURSES

      Voici la liste des courses:

      Riz
      Grains
      Saucisses
      Tomates
      Piments verts

      echo 1
      COURSES

      echo 2

      Voici ce que donne son exécution:


      Nous avons volontairement, pour des raisons pédagogiques, pollué le script avec "echo 1" et "echo 2".
      "echo 1" est lu par cat et ensuite renvoyé vers stdout.
      "echo 2" est une commande qui est exécutée.