Pane di farro mini-HOWTO

Questo mini-HOWTO spiega brevemente come fare il pane con la farina di farro.

Update: aggiornato il procedimento in seguito a successivi esperimenti! Ora il pane viene ancora più morbido!

Soddisfatto del mio 5° esperimento, voglio condividere con l’Internet la ricetta e le varie note d’interesse da tenere in mente.

La ricetta che ho seguito inizialmente prevede:

  • 300g di farina di farro (nel mio caso integrale, ma fate come vi pare)
  • 100g di farina bianca (tipo 00)
  • 250ml d’acqua tiepida
  • 3 o 4g di lievito di birra
  • uno o due cucchiaini di sale, secondo i gusti
  • un paio di cucchiai d’olio d’oliva

A questa lista, nell’ultimo esperimento ho provato ad aggiungere anche:

  • un cucchiaino di zucchero bianco

per favorire la lievitazione.

Strumenti necessari

  • contenitore graduato o bilancia per misurare sia la farina che l’acqua
  • contenitore per scaldare l’acqua (pentola o bollitore)
  • contenitore per lasciare il lievito ad “attivarsi” nell’acqua (una ciotolina grande abbastanza per contenere 250ml d’acqua)
  • scodella per impastare il pane (vedi note più avanti)
  • forno (eh)
  • teglia adatta al summenzionato forno
  • guanti da forno per maneggiare la teglia bollente
  • carta da forno
  • stoviglie varie: cucchiai, cucchiaini, coltelli, etc
  • un panno morbido e pulito (nel mio caso, di cotone)

Preparativi

La prima cosa da fare è mettere l’acqua a scaldare: non serve farla bollire, vi servirà tiepida, cioè più calda della temperatura ambiente, ma non abbastanza da scottarvi se ci mettete un dito dentro.

Mentre l’acqua si scalda, iniziate a misurare la farina.

Nota importante: non mettete via la farina dopo averla misurata! Quasi sicuramente ve ne servirà qualche altro pizzico durante la lavorazione.

Una volta che l’acqua è tiepida, mettetela in una ciotolina col lievito e un cucchiaino di zucchero, mescolate un po’ e lasciate il composto da parte: dopo qualche minuto dovrebbe fare una bella schiuma scura tipo quella della Guinness. Quello è il Segno[tm] che il lievito si è “attivato” correttamente.

Nota: l’acqua troppo fredda non “attiva” il lievito, mentre quella troppo calda lo uccide. Non esagerate in un senso o nell’altro!

Mentre aspettate che il lievito si attivi, mettete nella Scodella Per Impastare Il Pane tutta la farina e il sale, mischiateli bene e lasciate un buco al centro (la cosiddetta “fontanella”), dove più tardi verserete l’acqua col lievito.

Nota: la Scodella Per Impastare Il Pane è una scodella di acciaio inox piuttosto larga con il fondo in gomma per mantenerla ferma e attutire un po’ le botte sul tavolo durante la lavorazione dell’impasto. Geniale.

Scodella Per Impastare Il Pane

Nota: c’è chi dice di mettere il sale successivamente, perché può rallentare/diminuire la lievitazione. Non ho ancora verificato come si comporta l’impasto facendo in quel modo, ma mettendolo a questo punto, nella mia limitata esperienza non si sono verificati problemi.

L’impasto

Quando l’acqua col lievito ha sviluppato una bella schiuma, versatela nel “buco” lasciato in mezzo alla farina nella Scodella Per Impastare Il Pane.

Aggiungete un paio di cucchiai d’olio.

Nota importante: come detto per la farina, non mettete via l’olio, ve ne servirà ancora un goccio più avanti.

Iniziate a impastare. Personalmente vi consiglio di farlo con una sola mano a questo punto, perché l’altra potrà servirvi per aggiungere farina, se necessario, e pulire le mani sporche di impasto è piuttosto complicato.

L’impasto sarà inizialmente molto appiccicaticcio, ma si asciugherà rapidamente, man mano che assorbe tutta la farina. Se rimane troppo appiccicoso, aggiungete poca farina per volta mentre continuate a impastare.

Dopo un paio di minuti l’impasto dovrebbe avere la consistenza “giusta” e non dovrebbe più restare appiccicato alle mani o alla Scodella e potrete impastarlo con entrambe le mani per qualche minuto ancora, in modo che la pasta si compatti ancora meglio.

A questo punto potete coprire la Scodella con un panno e mettere l’impasto a lievitare per un’ora e mezza. Io l’ho messo nel forno (spento!).

Reimpasto e seconda lievitazione

Passata l’ora e mezza sarà il momento di recuperare l’impasto, lavorarlo ancora un po’ e prepararlo per la successiva infornatura.

Se tutto è andato bene, l’impasto dovrebbe essere raddoppiato (!) di volume. Se è rimasto più o meno uguale, potete stenderlo con un mattarello, aggiungere olio e rosmarino e fare delle gustose schiacciatine, ma il pane ve lo potete scordare.

Dovrete lavorare ancora un po’ l’impasto con entrambe le mani. Se è molto appiccicoso e difficile da staccare dalla Scodella Per Impastare Il Pane, potete aggiungere un po’ di farina per asciugarlo un po’.

Dopo averlo lavorato per qualche minuto, prendete abbastanza carta da forno da coprire il fondo della teglia, bagnatela con un po’ d’acqua (per renderla più maneggevole!) e disponetela sul fondo della teglia.

Versate un po’ d’olio d’oliva sulla carta da forno e spandetelo in uno strato sottile a coprire tutta l’area (potete aiutarvi con un pennellino o usare direttamente le dita).

Togliete l’impasto dalla Scodella Per Impastare Il Pane e disponetelo sulla teglia nel formato che vi è più congeniale… personalmente trovo che con questa quantità di farina abbia senso fare due o quattro “panetti”, tagliando l’impasto e facendoci delle palline. È possibile anche lasciare l’impasto tutto insieme per fare un singolo “pane”, ma ho trovato che è più difficile da cuocere correttamente.

Una volta posizionati i panetti sulla teglia, ricopritela e lasciateli ancora in forno solo con la luce accesa a lievitare per un’altra ora e mezza.

Infornare!

Terminata la seconda fase di lievitazione, togliete l’impasto dal forno e accendete quest’ultimo a 240° (o al massimo se il vostro a 240° non arriva).

Mentre aspettate che il forno si scaldi, scoprite l’impasto, che sarà di nuovo cresciuto, e praticate con un coltello alcuni tagli nella parte superiore (ad esempio il classico taglio “a croce”), che permetteranno al pane di crescere ancora durante la cottura senza rompersi.

Appena il forno è caldo, infornate!

Per la cottura, io mi sto trovando bene con 15 minuti a 230° (il massimo per il mio forno), per fare una crosta bella croccante e poi altri 20-25 minuti a 200°.

Al momento di sfornare potrete usare il panno di cui sopra per maneggiare il pane bollente e metterlo a riposare finché non raggiunge una temperatura adatta al palato :)

Riferimenti

How to quickly install and configure Splunk Enterprise

As you may have noticed, I’m not a huge fan of proprietary, closed source software. And of course I ended up having to install Splunk for a client. So here’s a few notes on what I did to get it working.

I started following this guide with a few integrations here and there.

Install the Splunk Server

First thing, you need to download the server. You have to register for it (proprietary software).

I got the 64bit RPM for my CentOS 7 server and installed it with

yum install splunk-*-linux-2.6-x86_64.rpm
/opt/splunk/bin/splunk --answer-yes --no-prompt --accept-license enable boot-start
/opt/splunk/bin/splunk --answer-yes --no-prompt --accept-license start

This will automatically accept the license and setup the Splunk Server to start at boot time.

If everything worked correctly, you should be able to connect to your Splunk Server on:

url: http://your-server-name-or-ip:8000
user: admin
pass: changeme

If it doesn’t work, check if you have a firewall on your server machine and open port tcp/8000 if needed.

For more information on this step, I’ll referr you to the Fine Manual:

Configure the Splunk Server

The logical next step is to configure the Splunk Server to listen for incoming logs.

Assuming you didn’t change (yet) your Splunk Server user and password, you’ll need to run:

/opt/splunk/bin/splunk enable listen 9997 -auth admin:changeme
/opt/splunk/bin/splunk enable deploy-server -auth admin:changeme

For more information on this step, check:

Install the Splunk Universal Forwarder on clients

Now that the server side is configured, we need to setup a client to send some logs to it. Again, head off to the download page and grab the package you need.

For large scale deployment you might want to read about how to use user-seed.conf, so you can pre-seed your installation user and password. For this quick tutorial, we’ll skip that and run directly these commands:

yum -y install splunkforwarder-*-linux-2.6-x86_64.rpm
/opt/splunkforwarder/bin/splunk --answer-yes --no-prompt --accept-license enable boot-start
/opt/splunkforwarder/bin/splunk --answer-yes --no-prompt --accept-license start

Again, this will automatically accept the license and enable the forwarder at boot time.

For more information about this step:

Configure the Universal Forwarder

Once the forwarder is installed, you’ll need to configure it to talk to your server.

Please note that the user and password I’m using are those of the local splunk, not the Splunk Server.

/opt/splunkforwarder/bin/splunk add forward-server splunk-server:9997 -auth admin:changeme
/opt/splunkforwarder/bin/splunk set deploy-poll splunk-server:8089 -auth admin:changeme
/opt/splunkforwarder/bin/splunk enable deploy-client -auth admin:changeme
/opt/splunkforwarder/bin/splunk add monitor /var/log/nginx/error.log
/opt/splunkforwarder/bin/splunk restart

In my case I added /var/log/nginx/error.log to the files that will be monitored and sent to the server.

For more information about this step, check out:

Accessing your logs on the Splunk Server

At this point you should be able to log in your Splunk Server web interface, head to the “Search & Reporting” app, and search for your data, for example I used a simple query:

source="/var/log/web/nginx/error.log"

to make sure the data from my log files was ending up in Splunk.

Workaround for NFS share not mounted at boot

I had a couple of servers unable to mount a NFS share at boot time. My /etc/fstab was something like:

[... usual stuff ...]
nfs.domain.tld:/nfs /nfs  nfs4  _netdev,auto,rw,noexec,nodev,timeo=5,retry=5,retrans=5,rsize=32768,wsize=32768,proto=tcp,hard,intr  1 2

If I tried to mount it after boot, it would work without any problem.

After checking the basic stuff (services, network access, etc), I went to see if The Internet[tm] knew any better, and this suggestion was spot-on, for some reason that I couldn’t pinpoint, even if the mountpoint definition had a _netdev attribute, it seemed like the mount was failing to properly resolve the name during the boot.

For the moment I went for a quick workaround, there was two main options: either add the NFS server hostname to /etc/hosts, or switch to the IP address in /etc/fstab. I went for the latter because it’s simpler (less stuff can break), until I can find out why it doesn’t resolve the names during the boot.

How to exclude everything except a specific pattern with rsync

Just a quick tip (and reminder for me): if you want to rsync only a specific file, or pattern, and exclude everything else, the syntax is:

rsync -a --include="*/" --include="*your-pattern*" --exclude="*" /source/path/ /destination/path/

In my specific case I wanted to copy only gzipped files, and my command line was:

rsync -avP --include="*/" --include="*your-pattern*" --exclude="*" /source/path/ /destination/path/

The first --include directive allows rsync to descend into subdirectories, while the second provides the actual filename or pattern we want to access.

How to cleanup and shrink disk space usage of a Windows KVM virtual machine

We still need Windows VMs (sadly, for a few tools we’re trying to get rid of), and my VM grew so much that the image was up to 60Gb. With my laptop only having a 256Gb SSD, it was getting pretty crowded. So I set up to cleanup the Windows image and shrink it down as much as possible, and I managed to get it down to 13Gb.

Since I’m not very familiar with Windows, I leveraged the knowledge of the Internet and started cleaning my system using the tips from this article: I ran CCleaner, removed old files, uninstalled unused software. Then I went on to the “not obvious” ways to free space. I opened an administrator console and proceeded to remove shadow copies:

vssadmin delete shadows /for=c: /all

and I consolidated the Service Pack on disk, to get rid of a lot of backups from C:\windows\winsxs\:

dism /online /cleanup-image /spsuperseded

there’s a few more things you can do to save space in that directory, especially if you run Windows 8.1, Server 2012 or newer, it’s worth checking this Microsoft Technet article.

Once I cleaned up as much space as possible, I ran the Windows Defrag utility to cluster up the remaining data and then went on to fill the rest of the disk with zeroes. Think of it like doing dd if=/dev/zero of=/zero.img: you’re creating a file containing only zeroes, so that those clusters will result “empty” during the shrinking.

On Windows, the recommended tool to zero-fill your disk seems to be SDelete. I ran it as administrator in a cmd console:

sdelete -z c:

This took a long time. Hours. Best thing would probably have been to run it overnight: learn from my mistakes! :)

Note: if you have a thin disk (for example a qcow2 image), filling it up with zeroes will actually consume space on the host, up to the maximum size of the virtual disk. In my case, the image grew from a bit more than 60G to 200G. A necessary, and temporary, sacrifice.

ls -l /var/lib/libvirt/images/
[...]
-rw-r--r-- 1 root root 200G 31 dic 16.34 win7_orig.img

After SDelete finished running (and syncing to disk), I shut down the VM and prepared for the next step: shrinking the actual disk image. Thankfully, qemu-img allows you to convert to the same format. This will discard any empty cluster (remember? we filled them with zeroes, so they are empty!).

In my case, I ran two processes in parallel, because I wanted to see how much of a difference it would make to have a compressed image versus a non-compressed image, as suggested by this Proxmox wiki page:

cd /var/lib/libvirt/images/
qemu-img convert -O qcow2 win7_nocomp.img win7_orig.img &
qemu-img convert -O qcow2 -c win7_compress.img win7_orig.img &
watch ls -l

This process didn’t take too long, less than one hour, and the result was pretty interesting:

ls -l /var/lib/libvirt/images/
[...]
-rw-r--r-- 1 root root  13G  1 gen 18.13 win7_compress.img
-rw-r--r-- 1 root root  31G 31 dic 19.09 win7_nocomp.img
-rw-r--r-- 1 root root 200G 31 dic 16.34 win7_orig.img

The compressed image is less than half the non-compressed one, but you’ll use a bit more CPU when using it. In my case this is completely acceptable, because saving disk space is more important.

How to install and use SPICE for VMs in Debian, Ubuntu or Mint

SPICE is a suite of tools for interfacing with desktop-oriented Virtual Machines. I’ve been using it for a couple of years, on Fedora and CentOS systems, mostly for Windows VMs that I required for work.

Until recently, it was fairly complicated to get SPICE to work on Debian-based systems, but I’ve just installed and got it working on Mint. Thankfully, nowadays you don’t need to recompile anything. All the patches and support are included by default, and you need to install these packages:

# apt-get update
# apt-get install virt-manager libvirt-daemon python-spice-client-gtk qemu-kvm-spice virt-viewer spice-vdagent qemu-utils  gir1.2-spice-client-gtk-3.0 gir1.2-spice-client-gtk-2.0 gir1.2-spice-client-glib-2.0

After this, I just created a new VM with virt-manager and it had SPICE enabled by default.

For more information, I recommend checking:

RHCSA – Use grep and regular expressions to analyze text

Queste sono alcune note sull’utilizzo di grep basate sulla pagina man e sull’esperienza personale. I test sono stati fatti su una Scientific Linux 6 (prima ancora che uscisse CentOS 6).

Sintassi di base (la riga che inizia per # è un commento):

# grep pattern file(s)
grep '127.0.0.1' /etc/*
/etc/hosts:127.0.0.1 localhost localhost.localdomain
[...]

Di default, grep assume stdin come input file, quindi è possibile usarlo in cascata sull’output di altri comandi:

# comando1 | grep pattern
ifconfig | grep 'inet addr'
  inet addr:127.0.0.1  Mask:255.0.0.0

Con l’opzione -e è possibile specificare uno o più pattern:

# grep -e pattern1 -e pattern2 file(s)
grep -e Linux -e '127.0.0.1' /etc/*
/etc/hosts:127.0.0.1   localhost localhost.localdomain
[...]
/etc/redhat-release:Scientific Linux release 6.0 (Carbon)

Con l’opzione -i si ignorano maiuscole e minuscole (rallenta di molto l’esecuzione):

# creo un file contenente due righe, la prima contiene 'Foo'
echo 'Foo' > casetest.txt
# la seconda contiene 'foo' (minuscolo)
echo 'foo' >> casetest.txt
# con un grep normale, usando 'foo' (minuscolo) come pattern ottengo
grep foo casetest.txt
foo
# usando l'opzione -i invece
grep -i foo casetest.txt
Foo
foo

Con l’opzione -v si inverte l’output (stampa le righe che non corrispondono al pattern):

# usiamo il file di prima, aggiungiamo 'Bar'
echo Bar >> casetest.txt
# grep -v pattern file(s)
grep -v foo casetest.txt
# attenzione: non abbiamo usato -i, quindi 'Foo' viene trattato diversamente
# da 'foo' e, non facendo match sul pattern, viene stampato
Foo
Bar

Con -c, invece di scrivere le righe che corrispondono al pattern, grep stampa un conteggio di quante volte il pattern è contenuto in uno o più file:

# grep -c pattern file(s)
grep -c Linux /etc/*
/etc/dhcp:0
[...]
/etc/redhat-release:1

Con le opzioni -l e -L si ottengono delle liste di file che contengono o non contengono un pattern:

# grep -l pattern file(s)
grep -l Linux /etc/*
/etc/grub.conf
/etc/issue
/etc/issue.net
[...]

# grep -L pattern file(s)
grep -L Linux /etc/*
/etc/dhcp
/etc/yum.conf
[...]

L’opzione -H dice di stampare sempre il nome del file di fianco all’eventuale match. E’ il comportamento di default quando ci sono molti files (vedere esempi precedenti).

L’opzione -n attiva la scrittura del numero di riga di fianco ad ogni match:

# grep -n pattern file(s)
grep -n Linux /etc/*
/etc/grub.conf:14:title Scientific Linux (2.6.32-71.18.2.el6.x86_64)
[...]

Con l’opzione -Z grep userà un null byte come separatore dei file. Utile con -l o -L e in combinazione con altri comandi che possono usare in ingresso una lista di nomi di file separati da null, ad esempio xargs -0. Serve per gestire nomi di file contenenti spazi o altri caratteri speciali.

# grep -lZ pattern file(s) | comando -opzione_per_input_null
grep -lZ Linux /etc/* | xargs -0 ls -lh
lrwxrwxrwx. 1 root root   22  4 feb 17:04 /etc/grub.conf -> ../boot/grub/grub.conf
-rw-r--r--. 1 root root   58 24 feb 21:12 /etc/issue
-rw-r--r--. 1 root root   57 24 feb 21:12 /etc/issue.net
-rw-r--r--. 1 root root 1,9K 23 nov 19:53 /etc/mail.rc
-rw-r--r--. 1 root root 4,9K 23 nov 22:37 /etc/oddjobd.conf
lrwxrwxrwx. 1 root root   15  4 feb 17:00 /etc/rc.sysinit -> rc.d/rc.sysinit
-rw-r--r--. 1 root root   38 24 feb 21:12 /etc/redhat-release
-rw-r--r--. 1 root root 6,4K 24 nov 07:52 /etc/smartd.conf
-rw-r--r--. 1 root root  822 24 nov 23:50 /etc/sysctl.conf
lrwxrwxrwx. 1 root root   14 21 mar 05:00 /etc/system-release -> redhat-release

Le opzioni di contesto servono a specificare quante righe di contesto estrarre oltre alla riga che fa il match del pattern. Con -A si indicano le righe dopo (After), con -B quelle prima (Before) e con -C un numero di righe simmetrico sia prima che dopo (Context).

# stampa due righe prima e 5 dopo il match
grep -B2 -A5 Linux /etc/*
[...]
--
/etc/smartd.conf-# the 3w-xxxx driver. Start long self-tests Sundays between 1-2, 2-3, 3-4,
/etc/smartd.conf-# and 4-5 am.
/etc/smartd.conf:# NOTE: starting with the Linux 2.6 kernel series, the /dev/sdX interface
/etc/smartd.conf-# is DEPRECATED.  Use the /dev/tweN character device interface instead.
/etc/smartd.conf-# For example /dev/twe0, /dev/twe1, and so on.
/etc/smartd.conf-#/dev/sdc -d 3ware,0 -a -s L/../../7/01
/etc/smartd.conf-#/dev/sdc -d 3ware,1 -a -s L/../../7/02
/etc/smartd.conf-#/dev/sdc -d 3ware,2 -a -s L/../../7/03
--
[...]

L’opzione -r (o -R) attiva la ricerca ricorsiva nei percorsi indicati:

# grep -r pattern path(s)
grep -r Linux /etc/*
[...]

L’opzione -z permette di gestire liste di file separate da byte null (vedi -Z).

Pattern e regular expressions

I pattern da utilizzare con grep possono essere semplici stringhe, oppure espressioni regolari che permettono di avere il match su più stringhe.

# grep -e pattern1 -e pattern2 file(s)
grep -e 'foo' -e 'Foo' casetest.txt
Foo
foo
grep -e '[Ff]oo' casetest.txt
Foo
foo
grep -e '.oo' casetest.txt
Foo
foo

Abbiamo visto due sintassi basate su regular expression: nella prima si utilizza una bracket expression, cioè una lista di caratteri contenuti tra parentesi quadre. Nella seconda, invece, abbiamo utilizzato il punto (.) che farà il match con qualsiasi carattere.

Nel caso delle bracket expression, potremo specificare tutte le lettere (maiuscole e minuscole) che potranno soddisfare l’espressione, oppure invertire il controllo usando il circonflesso come primo carattere della bracket expression:

echo aoo >> casetest.txt
grep -e '[^abc]' casetest.txt
Foo
foo
grep -e '.oo' casetest.txt
Foo
foo
aoo

Attenzione: se il circonflesso appare a inizio riga, ma non all’interno di parentesi quadre, indica che l’espressione deve cominciare a inizio riga.

echo snafooz >> casetest.txt
grep -e '^foo' casetest.txt
foo
grep -e 'foo' casetest.txt
foo
snafooz

L’opposto del circonflesso è il dollaro, per trovare stringhe a fine riga:

grep -e 'foo$' casetest.txt
foo
grep -e 'foo' casetest.txt
foo
snafooz

In questo caso, foo è l’unica stringa della riga, quindi è sia a inizio che a fine riga, per verificarlo possiamo unire i controlli:

grep -e '^foo$' casetest.txt
foo

Tornando alle bracket expression, è possibile utilizzare un segno meno (-) per creare un range, per esempio potremmo voler fare il match di tutti i numeri:

seq 100 | grep -e '[0-9]7'
17
27
37
47
57
67
77
87
97

In questo caso seq ha generato la lista dei numeri da 1 a 100. L’espressione regolare diceva di fare il match solo di quelli che contenevano un numero da 0 a 9 seguito dal numero 7. Di default seq ha generato i numeri da 1 a 10 senza mettere uno zero prima del numero, quindi il 7 è stato saltato da grep, mentre tutti gli altri soddisfano l’espressione regolare e sono stati riportati nell’output.

Esistono anche espressioni speciali che indicano particolari classi di caratteri:

  • [:alpha:] indica tutti i caratteri alfabetici (equivale al doppio range [A-Za-z], tranne per il fatto che quest’ultimo può essere influenzato dal “locale” impostato)
  • [:digit:] tutti i numeri (equivale al range [0-9])
  • [:lower:] e [:upper:] rispettivamente i caratteri lowercase ([a-z]) e uppercase ([A-Z])
  • [:space:] i caratteri vuoti (spazio, tab, a capo)

Per una lista completa si veda il manuale.

echo '1foo' | grep '[[:digit:]][[:alpha:]]'
1foo
echo '1foo' | grep '[[:digit:]][[:digit:]][[:alpha:]]'
echo '1foo' | grep '[[:digit:]][[:alpha:]][[:alpha:]]'
1foo

Attenzione: le parentesi quadre sono state raddoppiate perché quelle più esterne iniziano la bracket expression, mentre quelle interne fanno parte del simbolo che rappresenta la classe (es. [:digit:]).

Le espressioni regolari (singoli caratteri, bracket expression, carattere punto) possono essere seguite da operatori di ripetizione, che specificano quante volte si deve ripetere l’espressione che li precede.

Il primo operatore di ripetizione è il carattere punto interrogativo (?) che indica che l’espressione che lo precede dev’essere assente o presente una sola volta, ad esempio:

echo forever >> casetest.txt
grep -E '[Ff]?oo' casetest.txt
Foo
foo
aoo
snafooz

Come potete vedere, anche aoo fa il match, perché soddisfa le due o consecutive anche se non soddisfa la presenza (opzionale, grazie al punto interrogativo) della f. Da notare che abbiamo utilizzato l’opzione -E per attivare le regexp (regular expression) estese.

Il secondo operatore è l’asterisco (*), questo modifica l’espressione precedente indicando che può essere presente zero o più volte:

grep -E 'sn.*z' casetest.txt
snafooz

In questo caso abbiamo usato il carattere jolly . unito all’asterisco per specificare “qualsiasi carattere, ripetuto qualsiasi numero di volte”.

L’operatore più (+), invece, specifica che l’espressione compaia una o più volte:

grep -E 'o+' casetest.txt
Foo
foo
aoo
snafooz
forever

Come vedete, c’è stato il match sia di forever che di foo.

Esiste un altro operatore che permette di specificare in modo raffinato il numero di ripetizioni: tra parentesi graffe ({}) si può specificare il valore preciso {n} o un range {n,m} o un numero minimo {n,} o massimo {,m} di volte. Per esempio, proviamo a trovare tutti gli indirizzi IP in /etc/:

grep -E '([[:digit:]]+\.){3}[[:digit:]]+'
/etc/hosts:127.0.0.1   localhost localhost.localdomain
/etc/networks:default 0.0.0.0
/etc/networks:loopback 127.0.0.0
/etc/networks:link-local 169.254.0.0

Spieghiamo l’espressione regolare: cercherà uno o più numeri ([[:digit:]]+) seguiti da un punto (\.) e questo gruppo (raggruppato tra parentesi tonde) deve ripetersi tre volte ({3}) ed essere seguito da un altro gruppo di uno o più numeri.

È possibile anche creare alternative tra due espressioni, separandole con un pipe (|):

grep -E 'Foo|Bar' casetest.txt
Foo
Bar