J'en ai rêvé, Harel Ben-Attia l'a fait.
Utiliser des fichiers texte comme des tables SQL.
C'est ce que propose de faire la commande q.
Ce programme est développé en python.
Pour fonctionner, il utilise donc python 2.4 (minimum) et le module sqlite3.
Il est possible d'utiliser des fichiers texte dont le séparateur de colonne (par défaut) est l'espace.
N'importe quel autre séparateur est utilisable à condition de l'indiquer à l'aide de l'option -d
Si le fichier texte contient une ligne d'en-tête, il est possible de l'indiquer à l'aide de l'option -H et cela permet d'utiliser les en-têtes comme nom de colonne dans les requêtes SQL.
L'option -z permet d'utiliser des fichiers compressés avec gzip.
Le projet est disponible ici.
Un paquet RPM est disponible pour l'installation.
Pour les distributions Debian/Ubuntu, utiliser le programme alien pour convertir le paquet RPM en DEB.
Pour l'installtion, sous Debian/Ubuntu, après conversion du paquet :
$ dpkg --install q_xxx_all.deb
Les différentes utilisations possibles :
Utiliser la commande q derrière un pipe
Par exemple, la commande ls -l retourne le contenu d'un répertoire structuré en colonne.
Par conséquent, du fait que le retour de cette commande soit structuré, il est possible de l'envoyer à la commande q via un pipe et d'y effectuer des petites requêtes SQL.
$ ls -l /var/log
-rw-r--r-- 1 root root 3554 Mar 12 14:09 alternatives.log
-rw-r--r-- 1 root root 1208 Feb 21 10:51 alternatives.log.1
-rw-r--r-- 1 root root 246 Jan 27 18:17 alternatives.log.2.gz
-rw-r--r-- 1 root root 385 Jan 6 21:10 alternatives.log.3.gz
-rw-r--r-- 1 root root 539 Nov 22 08:16 alternatives.log.4.gz
-rw-r--r-- 1 root root 276 Oct 24 16:47 alternatives.log.5.gz
-rw-r--r-- 1 root root 948 Sep 23 22:35 alternatives.log.6.gz
drwxr-xr-x 2 root root 4096 Mar 1 05:00 apt
-rw-r----- 1 syslog adm 370529 Mar 12 14:16 auth.log
Le résultat est structuré en 9 colonnes.
$ ls -l /var/log | q -b "select * from -"
total 4164
-rw-r--r-- 1 root root 3554 Mar 12 14:09 alternatives.log
-rw-r--r-- 1 root root 1208 Feb 21 10:51 alternatives.log.1
-rw-r--r-- 1 root root 246 Jan 27 18:17 alternatives.log.2.gz
-rw-r--r-- 1 root root 385 Jan 6 21:10 alternatives.log.3.gz
-rw-r--r-- 1 root root 539 Nov 22 08:16 alternatives.log.4.gz
-rw-r--r-- 1 root root 276 Oct 24 16:47 alternatives.log.5.gz
-rw-r--r-- 1 root root 948 Sep 23 22:35 alternatives.log.6.gz
drwxr-xr-x 2 root root 4096 Mar 1 05:00 apt
-rw-r----- 1 syslog adm 370722 Mar 12 14:39 auth.log
Pour lire les données sur l'entrée standard, il faut utiliser le tiret "-" en nom de table.
L'option -b permet d'afficher le résultat aligné en colonne.
$ ls -l /var/log | q -b "select c9 from -"
alternatives.log
alternatives.log.1
alternatives.log.2.gz
alternatives.log.3.gz
alternatives.log.4.gz
alternatives.log.5.gz
alternatives.log.6.gz
apt
auth.log
On affiche uniquement le nom des fichiers correspondant donc au contenu de la colonne 9
$ ls -l /var/log | q -b "select c9, c5 from -"
alternatives.log 3554
alternatives.log.1 1208
alternatives.log.2.gz 246
alternatives.log.3.gz 385
alternatives.log.4.gz 539
alternatives.log.5.gz 276
alternatives.log.6.gz 948
apt 4096
auth.log 370722
On ajoute la taille de chaque fichier.
Effectuer des count et des sum etc etc ...
$ ls -l /var/log | sed '1d' | q -b "select count(*), sum(c5) from -"
54 4386404
Attention, j'ai ajouté la commande sed '1d' car la commande ls -l affiche sur la première ligne la taille totale des fichiers.
On peut même effectuer des opérations
$ ls -l /var/log | sed '1d' | q -b "select count(*), sum(c5)/1024 from -"
54 4283
La clause "order by" existe aussi.
$ ls -l /var/log | sed '1d' | q -b "select c9, c5 from - order by c5"
btmp 0
btmp.1 0
init.fifo 0
vsftpd.log 0
boot 1
dmesg 1
kern.log 1
lpr.log 1
mail.err 1
user.log 1
En ordre inverse
$ ls -l /var/log | sed '1d' | q -b "select c9, c5 from - order by c5 desc"
auth.log.0 1067312
mail.info 923064
mail.log 923064
messages 457260
auth.log 371108
lastlog 292292
auth.log.1.gz 70783
dpkg.log 37630
daemon.log 29013
syslog.0 24504
Idem avec la clause "where"
$ ls -l /var/log | sed '1d' | q -b "select c9, c5 from - where c9 like 'a%' order by c5 desc"
auth.log.0 1067312
auth.log 371108
auth.log.1.gz 70783
apt 4096
alternatives.log 3554
alternatives.log.1 1208
alternatives.log.6.gz 948
alternatives.log.4.gz 539
alternatives.log.3.gz 385
alternatives.log.5.gz 276
Et avec des fichiers maintenant
Je crée un fichier pour l'exemple.
$ ls -l /var/log | sed '1d' > listVarLog
Et j'effectue un "select" directement sur le fichier
$ q -b "select * from listVarLog"
-rw-r--r-- 1 root root 3554 Mar 12 14:09 alternatives.log
-rw-r--r-- 1 root root 1208 Feb 21 10:51 alternatives.log.1
-rw-r--r-- 1 root root 246 Jan 27 18:17 alternatives.log.2.gz
-rw-r--r-- 1 root root 385 Jan 6 21:10 alternatives.log.3.gz
-rw-r--r-- 1 root root 539 Nov 22 08:16 alternatives.log.4.gz
-rw-r--r-- 1 root root 276 Oct 24 16:47 alternatives.log.5.gz
-rw-r--r-- 1 root root 948 Sep 23 22:35 alternatives.log.6.gz
drwxr-xr-x 2 root root 4096 Mar 1 05:00 apt
-rw-r----- 1 syslog adm 371301 Mar 12 15:16 auth.log
-rw-r----- 1 syslog adm 1067312 Feb 23 05:00 auth.log.0
Si mon fichier n'est pas dans mon répertoire courant...
$ q -b "select * from /root/listVarLog"
-rw-r--r-- 1 root root 3554 Mar 12 14:09 alternatives.log
-rw-r--r-- 1 root root 1208 Feb 21 10:51 alternatives.log.1
-rw-r--r-- 1 root root 246 Jan 27 18:17 alternatives.log.2.gz
-rw-r--r-- 1 root root 385 Jan 6 21:10 alternatives.log.3.gz
-rw-r--r-- 1 root root 539 Nov 22 08:16 alternatives.log.4.gz
-rw-r--r-- 1 root root 276 Oct 24 16:47 alternatives.log.5.gz
-rw-r--r-- 1 root root 948 Sep 23 22:35 alternatives.log.6.gz
drwxr-xr-x 2 root root 4096 Mar 1 05:00 apt
-rw-r----- 1 syslog adm 371301 Mar 12 15:16 auth.log
-rw-r----- 1 syslog adm 1067312 Feb 23 05:00 auth.log.0
... J'indique le chemin complet dans ma requête.
Avec une ligne d'en-tête.
$ head listVarLog
PERMS INODE USER GROUP SIZE MONTH DAY TIME FILE
-rw-r--r-- 1 root root 3554 Mar 12 14:09 alternatives.log
-rw-r--r-- 1 root root 1208 Feb 21 10:51 alternatives.log.1
-rw-r--r-- 1 root root 246 Jan 27 18:17 alternatives.log.2.gz
-rw-r--r-- 1 root root 385 Jan 6 21:10 alternatives.log.3.gz
-rw-r--r-- 1 root root 539 Nov 22 08:16 alternatives.log.4.gz
-rw-r--r-- 1 root root 276 Oct 24 16:47 alternatives.log.5.gz
-rw-r--r-- 1 root root 948 Sep 23 22:35 alternatives.log.6.gz
drwxr-xr-x 2 root root 4096 Mar 1 05:00 apt
-rw-r----- 1 syslog adm 371301 Mar 12 15:16 auth.log
$ q -b -H "select * from listVarLog"
-rw-r--r-- 1 root root 3554 Mar 12 14:09 alternatives.log
-rw-r--r-- 1 root root 1208 Feb 21 10:51 alternatives.log.1
-rw-r--r-- 1 root root 246 Jan 27 18:17 alternatives.log.2.gz
-rw-r--r-- 1 root root 385 Jan 6 21:10 alternatives.log.3.gz
-rw-r--r-- 1 root root 539 Nov 22 08:16 alternatives.log.4.gz
-rw-r--r-- 1 root root 276 Oct 24 16:47 alternatives.log.5.gz
-rw-r--r-- 1 root root 948 Sep 23 22:35 alternatives.log.6.gz
drwxr-xr-x 2 root root 4096 Mar 1 05:00 apt
-rw-r----- 1 syslog adm 371301 Mar 12 15:16 auth.log
-rw-r----- 1 syslog adm 1067312 Feb 23 05:00 auth.log.0
Exécuter une requête avec le nom des champs.
$ q -b -H "select FILE, SIZE from listVarLog"
alternatives.log 3554
alternatives.log.1 1208
alternatives.log.2.gz 246
alternatives.log.3.gz 385
alternatives.log.4.gz 539
alternatives.log.5.gz 276
alternatives.log.6.gz 948
apt 4096
auth.log 371301
auth.log.0 1067312
$ q -b -H "select FILE, SIZE, MONTH from listVarLog where MONTH = 'Mar'"
alternatives.log 3554 Mar
apt 4096 Mar
auth.log 371301 Mar
btmp 0 Mar
daemon.log 29013 Mar
dpkg.log 37630 Mar
lastlog 292292 Mar
mail.info 923064 Mar
mail.log 923064 Mar
messages 457260 Mar
En utilisant un délimiteur de colonne autre que l'espace.
Avec le fichier /etc/passwd par exemple, dont le délimiteur est ":"
$ q -b -d':' -D'|' "select * from /etc/passwd"
root |x|0 |0 |root |/root |/bin/bash
daemon |x|1 |1 |daemon |/usr/sbin |/bin/sh
bin |x|2 |2 |bin |/bin |/bin/sh
sys |x|3 |3 |sys |/dev |/bin/sh
sync |x|4 |65534|sync |/bin |/bin/sync
games |x|5 |60 |games |/usr/games |/bin/sh
man |x|6 |12 |man |/var/cache/man |/bin/sh
lp |x|7 |7 |lp |/var/spool/lpd |/bin/sh
mail |x|8 |8 |mail |/var/mail |/bin/sh
news |x|9 |9 |news |/var/spool/news |/bin/sh
J'indique le délimiteur du fichier avec l'option -d':' et j'en profite pour modifier le délimiteur de sortie avec l'option -D'|'
Et les jointures entre fichier
$ q -b -d':' -D'|' "select a.c3, a.c1, a.c4, b.c1 from /etc/passwd a left join /etc/group b on a.c4 = b.c3"
0 |root |0 |root
1 |daemon |1 |daemon
2 |bin |2 |bin
3 |sys |3 |sys
4 |sync |65534|nogroup
5 |games |60 |games
6 |man |12 |man
7 |lp |7 |lp
8 |mail |8 |mail
9 |news |9 |news
Cette requête permet d'afficher l'uid, le user, le gid et le group pour chaque ligne du fichier /etc/passwd et en effectuant une jointure avec le fichier /etc/group et en indiquant les colonnes permettant d'effectuer la jointure.
Pour l'instant, seul le "SELECT" peut-être utilisé.
La syntaxe utilisée est celle du SGDB
SQLite