I programmi che funzionano come filtro agiscono facendo delle modifiche a quello che leggono dal proprio standard input e generando di conseguenza uno standard output.
Alcuni esempi semplici:
cat -n
tac
rev
sort
, sort -n
, sort -r
head
tail
Il programma cut "preleva" alcuni campi delle righe di input.
$ getent passwd root | cut -d: -f7
/bin/bash
Il programma expand converte i caratteri di tabulazione in spazi. Il programma unexpand fa l'opposto.
$ cat bashscript
#!/bin/bash
for i in $@
do
echo $i
done
$ cat bashscript | expand -t4
#!/bin/bash
for i in $@
do
echo $i
done
$ cat bashscript | expand -t1
#!/bin/bash
for i in $@
do
echo $i
done
Il programma fmt formatta il testo a una specifica lunghezza della riga.
$ cat testolungo.txt
Un filtro software è un programma che trasforma dati in base a criteri predeterminati.
Tra i programmi di tipo filtro, esistono dei software in grado di selezionare pagine su Internet in base ad alcuni
[snip]
(dalla Wikipedia)
$ cat testolungo.txt | fmt
Un filtro software è un programma che trasforma dati in base a
criteri predeterminati. Tra i programmi di tipo filtro, esistono dei
software in grado di selezionare pagine su Internet in base ad alcuni
[snip]
giochi, ecc.). (dalla Wikipedia)
$ cat testolungo.txt| fmt -w 40
Un filtro software è un programma
che trasforma dati in base a criteri
predeterminati. Tra i programmi di
[snip]
(dalla Wikipedia)
I programmi head e tail mostrano, rispettivamente, le prime e le ultime righe (o i primi e gli ultimi byte, a seconda dell'opzione) di un file.
Se si indica di leggere più di un file, viene mostrata una riga di intestazione per ciascun file.
$ head -n2 /etc/services /etc/protocols
==> /etc/services <==
# Network services, Internet style
#
==> /etc/protocols <==
# Internet (IP) protocols
#
$ tail -n2 /etc/services /etc/protocols
==> /etc/services <==
fido 60179/tcp # fidonet EMSI over TCP
# Local services
==> /etc/protocols <==
sctp 132 SCTP # Stream Control Transmission Protocol
fc 133 FC # Fibre Channel
Notare che l'opzione abbreviata -2
funziona con head
ma non con tail
.
Il programma tail può funzionare anche per seguire in tempo reale la crescita di un file (utile per i log).
Il programma join
stampa una linea per ciascuna coppia di linee provenienti da due file con un campo in comune (con lo stesso valore), un po' come con un join tra tabelle in una base di dati.
$ cat tipi-mime
image/gif gif
image/jpeg jpeg jpg jpe
image/png png
image/tiff tiff tif
image/x-ms-bmp bmp
image/x-photoshop psd
$ cat lista-defaults
image/bmp eog
image/gif eog
image/jpeg eog
image/jpg eog
image/png eog
image/tiff gimp-2.2
image/x-psd gimp-2.2
$ join tipi-mime lista-defaults
image/gif gif eog
image/jpeg jpeg jpg jpe eog
image/png png eog
image/tiff tiff tif gimp-2.2
Importante: i due file devono essere ordinati rispetto ai campi di join.
Il programma nl numera le righe dei file di input tenendo in considerazione l'eventuale presenza di stringhe speciali (es. \:
) per la delimitazione di intestazione, corpo e piè di pagina.
$ cat testo.txt
\:\:\:
I filtri
\:\:
Un filtro software è un
programma che trasforma
dati in base a criteri
predeterminati.
\:
Filtro (wikipedia)
$ nl testo.txt
I filtri
1 Un filtro software è un
2 programma che trasforma
3 dati in base a criteri
4 predeterminati.
Filtro (wikipedia)
Il programma od mostra il contenuto di un file in ottale, esadecimale e in vari altri formati.
$ cat testoacapo
testo
a
capo
$ od -t a testoacapo
0000000 t e s t o nl a nl c a p o nl
0000015
$ od -t c testoacapo
0000000 t e s t o \n a \n c a p o \n
0000015
$ od -t x1 testoacapo
0000000 74 65 73 74 6f 0a 61 0a 63 61 70 6f 0a
0000015
$ od -t x4 testoacapo
0000000 74736574 0a610a6f 6f706163 0000000a
0000015
Il programma paste accosta le linee corrispondenti di uno o più file.
$ cat nomi
mario
giovanni
luisa
$ cat cognomi
rossi
bianchi
neri
$ paste nomi cognomi
mario rossi
giovanni bianchi
luisa neri
$ paste -d' ' nomi cognomi
mario rossi
giovanni bianchi
luisa neri
$ paste -s -d\; nomi cognomi
mario;giovanni;luisa
rossi;bianchi;neri
Il programma pr converte il file di input in una versione impaginata, con intestazioni e piè di pagina.
$ cat testolungo.txt | fmt -w 30 | pr -l 12 -W 30 -h "Documento sui filtri software"
Il programma uniq elimina righe duplicate adiacenti; per questo motivo è spesso usato dopo sort
.
Il programma wc conta i caratteri, le parole e le righe.
$ getent passwd | cut -d: -f7 | sort | uniq # quali sono le shell impostate
/bin/bash
/bin/false
/bin/sh
/bin/sync
/usr/sbin/nologin
$ getent passwd | cut -d: -f7 | sort | uniq | wc -l # quante sono le shell impostate
5
Il programma grep
mantiene le righe che soddisfano (o non soddisfano) un certo criterio costituito da una espressione regolare.
$ getent services | grep http
www 80/tcp http
https 443/tcp
https 443/udp
getent services | grep ^http
https 443/tcp
https 443/udp
$ getent services | head -5 | grep -v udp
tcpmux 1/tcp
echo 7/tcp
discard 9/tcp sink null
Con grep è anche possibile contare le righe in cui c'è la corrispondenza, mostrare le righe adiacenti, ecc.
Il programma gawk
agisce sui singoli campi, riformattandoli, usandoli per fare delle operazioni, ecc.
Per i prossimi esempi, immaginiamo di avere un file di testo chiamato datipersonali. Innanzitutto diamo un'occhiata al suo contenuto:
$ cat datipersonali
12 alice pordenone
24 berto udine
36 camilla trieste
48 daniele gorizia
60 elisabetta treviso
Con gawk
possiamo estrarre i singoli campi:
$ cat datipersonali | gawk '{ print $3 }'
pordenone
udine
trieste
gorizia
treviso
$ cat datipersonali | gawk '{ print $2 }'
alice
berto
camilla
daniele
elisabetta
Con gawk
possiamo estrarre i singoli campi:
$ cat datipersonali | gawk '{print $0}' # tutti i campi
12 alice pordenone
24 berto udine
36 camilla trieste
48 daniele gorizia
60 elisabetta treviso
$ cat datipersonali | gawk 'BEGIN {n=3} {print $n}'
pordenone
udine
trieste
gorizia
treviso
Con gawk
possiamo fare dei test sul valore dei singoli campi:
$ cat datipersonali | gawk '{ if ($2 == "alice") print $3 }'
pordenone
$ cat datipersonali | gawk '{ if ($1 <= 40) print $2 }'
alice
berto
camilla
Con gawk
possiamo fare operazioni sui valori dei singoli campi:
$ cat datipersonali | gawk '{s += $1} END {print s}'
180
$ cat datipersonali | gawk 'BEGIN {s=10000} {s += $1} END {print s}'
10180
Possiamo indicare ciò che consideriamo separatore dei campi:
$ getent passwd | gawk 'BEGIN {FS=":"} {print $1}' | tail -5
andrea_p
federica_p
marco_p
monica_s
mattia_z
Possiamo lavorare solo sulle righe che contengono una determinata espressione regolare:
$ cat datipersonali | gawk '/ab/ {print $3}'
treviso
... oppure controllare la corrispondenza di un singolo campo:
$ cat datipersonali | gawk '{if ($2 ~ /a/) print $3}'
pordenone
trieste
gorizia
treviso
$ cat datipersonali | gawk '{if ($2 !~ /a/) print $3}'
udine
Si supponga di voler trovare tutti i file di un certo tipo (restituito dal comando file
) in una directory e in tutte le sue sottodirectory. Ad esempio, tutti i file di tipo text della directory /sbin.
Una pipeline risolve il problema:
$ find /sbin -type f| xargs -i file {} | gawk \
'{ FS=":"; if ($2 ~ /text/) print $1}'
/sbin/MAKEDEV
/sbin/insmod_ksymoops_clean
/sbin/kernelversion
/sbin/shadowconfig
/sbin/fsck.nfs
/sbin/hotplug
/sbin/mdrun
/sbin/update-modules.modutils
/sbin/update-modules
...
I campi dell'input possono essere ricalcolati/riformattati.
Ad esempio, il log di squid presenta righe in cui nel primo campo c'è il numero di secondi dall'epoch, ma potremmo desiderare dei valori più comprensibili:
$ cat squid_access.log
1173783723.856 337 192.168.3.2 TCP_MISS/2...
1173783723.908 561 192.168.3.2 TCP_MISS/2...
1173783724.113 1952 192.168.3.2 TCP_MISS/2...
$ cat squid_access.log | gawk '{$1=strftime("%F_%T",$1); print $0}'
2007-03-13_12:02:03 337 192.168.3.2 TCP_MISS/2...
2007-03-13_12:02:03 561 192.168.3.2 TCP_MISS/2...
2007-03-13_12:02:04 1952 192.168.3.2 TCP_MISS/2...
Sed agisce sulle righe dell'input in diversi modi.
L'uso più comune ha a che fare con la sostituzione di stringhe:
$ getent services | head -3 | sed 's/echo/ecco/'
tcpmux 1/tcp
ecco 7/tcp
ecco 7/udp
... ma anche:
$ getent services | head -3 | sed 'sa/a|a'
tcpmux 1|tcp
echo 7|tcp
echo 7|udp
Sed può selezionare gruppi di righe.
In base al contenuto:
$ getent services| sort | sed -n '/^fido/,/^ftp/p'
fido 60179/tcp
finger 79/tcp
font-service 7100/tcp xfs
font-service 7100/udp xfs
frox 2121/tcp
fsp 21/udp fspd
ftp 21/tcp
... oppure in base al numero di riga:
$ getent services| sort | cat -n | sed -n 12,18p
12 afs3-callback 7001/udp
13 afs3-errors 7006/tcp
14 afs3-errors 7006/udp
15 afs3-fileserver 7000/tcp bbs
16 afs3-fileserver 7000/udp bbs
17 afs3-kaserver 7004/tcp
18 afs3-kaserver 7004/udp