Utiliser le langage SQL sur n'importe quel fichier texte

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
Etiquettes: