Quando si scrive qualcosa sulla linea di comando, si può scoprire che la shell fa qualcosa, come ad esempio espandere caratteri speciali.
Questa espansione di pattern alla ricerca di nomi corrispondenti, si chiama globbing.

Situazione:

sim@idrogeno:~/dev/perl/markdown$ ls -1
index.html
index.html.tidy
index.text
Markdown_1.0.1
mathjax-MathJax-5a7e4d7
remarkable
test_multi.html
test_multi.pl
test_multi.txt

sim@idrogeno:~/dev/perl/markdown$ ls *html
index.html  test_multi.html

sim@idrogeno:~/dev/perl/markdown$ echo *html
index.html test_multi.html

La shell espande la stringa *html nelle eventuali corrispondenze trovate nei nomi dei file nella directory.

Nel caso la shell non trovi corrispondenze, tratta il pattern come una stringa qualsiasi.

sim@idrogeno:~/dev/perl/markdown$ echo *xyz
*xyz

man bash, paragrafo Pathname Expansion.
Dopo aver diviso le parole (word splitting), bash cerca ogni parola coi caratteri *, ? e [; se uno di questi compare la parola viene trattata come un pattern e rimpiazzata con una lista di nomi di file corrispondenti il pattern in ordine alfabetico.
Se non vi è alcuna corrispondenza, e l'opzione nullglob non è abilitata, la parola viene lasciata immutata - se nullglob è impostata, la parola viene rimossa dall'elenco.

Riguardo il Pattern Matching: ogni singolo carattere (esclusi quelli indicati sopra, nel caso non vengano "escapati" col backslash) che appare nel pattern corrisponde a se stesso.

  • * corrisponde a qualunque stringa
  • ? corrisponde a un qualunque singolo carattere
  • [...] (range expression) corrisponde a un qualunque carattere di quelli contenuti. [!...] o [^...] per negare la corrispondenza col carattere.
sim@idrogeno:~/dev/perl/markdown$ echo test_multi.[hp]*
test_multi.html test_multi.pl
sim@idrogeno:~/dev/perl/markdown$ echo test_multi.[!hp]*
test_multi.txt
sim@idrogeno:~/dev/perl/markdown$ echo test_multi.[^hp]*
test_multi.txt

In Perl il globbing funziona alla stessa maniera utilizzando l’operatore glob oppure il “diamond“:

my @images = glob "*.jpg"
my @all_files = glob "* .*"
# oppure
my @all_files = <* .*>

Ovviamente se si vogliono fare le cose per bene, si va con i directory handles (opendir, readdir, closedir).

La shell bash e find continuano ad emanare il loro esagerato fascino su di me, nonostante le insidie che presentano.

Su irc.freenode, c’è un canale #bash che trovo interessante solo da seguire come osservatore esterno.

Da man:

SYNOPSIS
       find [-H] [-L] [-P] [path...] [expression]

Lasciamo perdere le opzioni, e path è il path da cui cominciare la ricerca.
Le espressioni si suddividono in 3 categorie: options, tests, actions; il tutto è separato da operators – ed in mancanza di essi si suppone siano degli -and.

Test

Una delle cose più ganze sono i test; descrivo quelli che mi sono utili in condizioni comuni.

  • -empty : ritorna i file vuoti.
  • -name pattern : dove pattern e’ il nome del file da cercare, ed è meglio quotare il pattern per evitare che la shell espanda i caratteri speciali (ie: insomma, usare ‘*jpg’ invece del semplice *jpg). -iname è la versione case insensitive.
  • -type c : ritorna vero dove c è il tipo di file indicato (d per le directory, f per i file, l per i link simbolici, p per le pipe, s per i socket…).
  • -size nn : fa un test legato alla grandezza del file. Può gestire un prefisso +/- per indicare se il test deve essere su numeri maggiori o minori di quello indicato, e un suffisso c,k,M,G che indica rispettivamente byte, kilobyte, megabyte e gigabyte.
  • -perm mode : cerca i file con i permessi esatti indicati (ie: -perm 0644 cerca tutti i file con esattamente i permessi di -rw-r–r– )
  • -path pattern : fa un matching come -name, ma si basa sull’intera directory invece che solo sul (base)name del file e non tratta in maniera speciale i metacaratteri . e /.
  • -amin/-atime n : Ritorna vero se l’ultimo accesso (file utilizzato) è stato effettuato n minuti o giorni fa.
  • -mmin/-mtime n : Ritorna vero se l’ultima modifica al file è stata effettuata n minuti o giorni fa.

I valori numerici possono avere come prefisso nulla, un + (più) per indicare una cifra maggiore di quella indicata, e un – (meno) per indicare una cifra minore di quella indicata.

sim@idrogeno:~$ find . -maxdepth 1 -type f -size +1M

Trova tutti i file (-type f) al primo livello (-maxdepth 1, quindi non va nelle subdir) dato il path di partenza (.), con size maggiore di 1 Mega.

Opzioni

Le opzioni non mi sembrano particolarmente interessanti, quindi andate di man. :-P

  • -maxdepth nn : indica per quanti livelli discendere nella ricerca. 0 è la linea di comando, 1 è la dir attuali, 2 indica le subdir subito seguenti, ecc…
  • -mindepth nn : come sopra, ma non applica i test nelle dir indicate…
  • -mount/-xdev : non discende in directory che sono in altri filesystem – molto utile per evitare di girovagare fra mount di samba o altro…

Actions

Qui si comincia a ridere…
Le azioni fanno. Per l’esattezza di solito fanno qualcosa coi file che hanno passati i test. Alcune possono in definitiva essere pericolose – in quanto ottengono risultati.

  • -print : la più banale, innocua e semplice (e di default): stampa il risultato dei test. -print0 stampa con un \0 finale (no newline).
  • -ls : stampa info sui file che hanno superato i test come se si fosse digitato ls -dils per ognuno di essi. (d: visualizza il nome delle dir ma non il loro contenuto, i: visualizza l’inode del file, l: formato esteso, s: stampa la size in blocchi).
  • -exec comando \; : esegue l’argomento di -exec fino al ; (che ha un escape davanti per evitare di essere “mangiato” dalla shell). La stringa {} è rimpiazzata dal filename attuale – e deve essere escape’ata anch’essa. Il comando viene eseguito una volta per file match’ante.
  • -ok comando \; : funziona come -exec, ma chiede conferma.
  • -printf formato : visualizza seguendo il foramto tipico della printf del C.
  • -prune : se il file è una dir, non discende attraverso di essa.

Operatori

Gli operatori spesso non vengono capiti nelle espressioni di find, ma sono pochi e semplici da capire. Ricordo che se fra due espressioni non c’è alcun operatore, si assume ci sia -and.
Le parentesi ( )forniscono la precedenza da seguire, in casi ambigui.

  • ! / -not : negazione
  • -a / -and : and
  • -o / -or : or

Esempi:
* Ricerchiamo file vuoti nella nostra home:

sim@idrogeno:~$ find . -empty -and -print

Spiegazione: trova nel path . i file che passano il test -empty e stampa. notare che -print è assunto di default e gli -and sono messi in automatico fra le condizioni quando mancano; in pratica find -empty dice già a find di cercare tutti i file nella directory locale che superano il test di size zero, e li stampa a terminale.

* Ricerchiamo file dove l’utente non siamo noi nella nostra home.

sim@idrogeno:~$ find . -not -user sim -print

* Ricerchiamo file esagerati… (e le risposte non vi piaceranno)

sim@idrogeno:~$ find . -size +1G -ls

(Brutta cosa, mi ha fatto vedere questo:

7373607 1998756 -rw-------   1 sim      sim      2044723200 Aug 18 07:14
  ./.kde/share/apps/nepomuk/repository/main/data/virtuosobackend/soprano-virtuoso.db

e io non ho kde come DE… F@nku)

Manipolazioni interessanti di nomi di file:

sim@idrogeno:~$ find . -path ‘./.spamassassin’ -prune -or -name ‘*xml’ -size +1M -print -exec bash -c ‘echo ${0%.xml}-obeso.xml’ \{} \;

Dunque, questa è uno scherzo con echo, ma si possono fare cose ganze ovviamente con gli accorgimenti di questa riga.
In pratica find cerca in locale, se trova un path che si chiama ‘./.spamassassin’ lo evita (-prune), poi cerca i file con il nome che si conclude con xml, di grandezza superiore ad 1MB e li stampa con l’azione print, inoltre per ogni file esegue anche una shell bash che prende il comando da stringa (con -c); echo ${0%.xml}-obeso.xml semplicemente prende il nome del file sotto analisi con {}, lo passa a $0 (in quanto primo argomento dopo la stringa), ne fa un espansione tagliata con %.xml e ci aggiunge il resto.

Grazie a stringhe come l’ultima, si possono eseguire compiti anche molto complessi con find, -exec e bash insieme. :-)

Orco boia, bisognerebbe conoscerlo bene sto benedetto bash… :-(

Il carattere $ introduce l’espansione di un parametro:

sim@idrogeno:~$ saluti=‘Saluti da H’
sim@idrogeno:~$ echo $saluti
Saluti da H

Fin qua easy.

Il parametro da espandere può essere racchiuso fra parentesi graffe { } per evitare ambiguità: $saluti è identico a ${saluti}. E anche qua, easy.

Cose più ficche sono queste:

Default values: ${parameter:-word}
Assign: ${parameter:=word}
${parameter:?word}
${parameter:+word}
${parameter:offset}
Substring: ${parameter:offset:length}
...

Il primo costrutto funziona come un operatore ternario: parameter ? parameter : word.
Il secondo fa anche l’assegnamento.
Ecc…

sim@idrogeno:~$ echo ${saluti:-‘Saluti da Mario’}
Saluti da H
sim@idrogeno:~$ echo ${greetings:-‘Saluti da Mario’}
Saluti da Mario

$saluti era già assegnato, quindi non è stato cambiato il suo contenuto. $greetings invece era vuoto, quindi è stato stampata a schermo l’alternativa (“Saluti da Mario”).
Comunque, se stampiamo $greetings

sim@idrogeno:~$ echo $greetings

sim@idrogeno:~$ echo ${saluti:=‘Saluti da Mario’} ${greetings:=‘Saluti da Pippo’}
Saluti da H Saluti da Pippo
sim@idrogeno:~$ echo $greetings
Saluti da Pippo

$greetings era vuoto, perchè :- non assegna. Con := abbiamo l’assegnamento se la variabile non è null o undef.
:+ funziona alla rovescia: non rimpiazza se la variabile ($caio) è vuota, ma se ne prendiamo una con già un contenuto ($greetings) ritorna il valore alternativo.

sim@idrogeno:~$ echo ${caio:+pippo}

sim@idrogeno:~$ echo ${greetings:+pippo}
pippo
sim@idrogeno:~$ echo $greetings
Saluti da Pippo

Come si nota dall’ultima riga, :+ non assegna il nuovo valore (che quindi rimane quello precedente), ma ritorna solo un’alternativa al check se il parametro è vuoto.

L’espansione con :? serve a produrre messaggi di errore con il testo di word nel caso il parametro sia null/undef.

sim@idrogeno:~$ echo -e ${caio:?Questo \$caio è proprio vuoto}
bash: caio: Questo $caio è proprio vuoto

Riferimenti: Bash Reference Manual

Di recente mi sono imbattuto in un problemino minchione: avere una sequenza di numeri in ordine inverso (cioè non da 1 a 20 ma da 20 a 1). Fin qui tutto easy.

Di solito se devo avere una sequenza uso appunto seq:

$ seq 1 10

Che stampa appunto i numeri da 1 a 10.
Il problema è che il contrario non mi funzionava.

$ seq 10 1

Nada.

Comunque, mentre cogitavo su questo e quello, e mentre mischiavo seq con sort mi sono imbattuto in una finezza bash che non conoscevo: la brace expansion.

Le brace expansion permettono di creare un output multiplo:

sim@idrogeno:~$ echo {Zio,Gastone}Paperone
ZioPaperone GastonePaperone

In effetti anche:

sim@idrogeno:~$ echo {20..1}
20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1

e

sim@idrogeno:~$ echo 0{1..20}
01 02 03 04 05 06 07 08 09 010 011 012 013 014 015 016 017 018 019 020

Inoltre si possono creare più concatenazioni:

sim@idrogeno:~$ for stringa in {A..C}{1..3}{x..z}; do echo -n "$stringa "; done
A1x A1y A1z A2x A2y A2z A3x A3y A3z B1x B1y B1z B2x B2y B2z B3x B3y B3z C1x C1y C1z C2x C2y C2z C3x C3y C3z

Perchè possono risultare comode?
Beh, ad esempio, come spiegato nella pagina linkata, per questo:

sim@idrogeno:~$ ls /usr/lib/perl{5,/5.10}/Data/
/usr/lib/perl/5.10/Data/:
Dumper.pm

/usr/lib/perl5/Data/:
Alias.pm

o questo

sim@idrogeno:~$ mkdir -v tmp/{test,a,z}
mkdir: created directory ‘tmp/test’
mkdir: created directory ‘tmp/a’
mkdir: created directory ‘tmp/z’

sim@idrogeno:~$ rmdir -v tmp/{test,a,z}
rmdir: removing directory, ‘tmp/test’
rmdir: removing directory, ‘tmp/a’
rmdir: removing directory, ‘tmp/z’

;-)

More »

Il bello di una box nuova, è che ce la si può personalizzare.
Dopo aver ricompilato il kernel (quello FreeBSD m’è sembrato molto più semplice di quello Linux), rodio è stata sottoposta ad alcune modifiche necessarie.

Installazione dai ports della shell bash, del bash completition e di vim, per cominciare.

Altra cosa utile, è stato attivare il server ssh.

In /etc/rc.conf aggiungere la riga:
sshd_enable="YES"
Poi:
# /etc/rc.d/sshd start

Altri programmi installati: lsof, mutt, nmap, portaudit, ssh2, wget.

E poi il webserver… Per provare questa volta mi sono dedicato a lighttpd – e mi è parso davvero simpatico. :)
(Grazie Jack per la dritta di secoli fa… che ho deciso di sfruttare ora.)

Riferimenti:
* Documentazione su FreeBSD
* FreeBSD Diary
* Info su Openssh.

Se invece che compilare ogni singolo port, si preferisce prendere i pacchetti precompilati, leggere qua.

Colori dei promptGià tempo addietro avevo parlato dei colori di ls, legati indissolubilmente a quelli di bash.

Ho deciso di sistemare un po’ il prompt di root e user sulle diverse macchine (vedi ~/.bashrc, variabile PS1), anche se non sono ancora del tutto convinto. Visto che mi piacciono gli sfondi scuri (con scritte chiare), ho scelto il rosa per il percorso, e il ciano per le utenze; le box hanno colori diversi (per ora): idrogeno è giallo, neon è verde, radon lo farò blu chiaro.
Non sono ancora convinto di voler tutto questo arcobaleno, ma magari mi setterò presto su qualcosa di leggibile.

Per la cronaca: l’utenza su Idrogeno ha la PS che segue:

PS1=’\[\033[0;36m\]\u\[\033[1;00m\]@\[\033[1;33m\]\h\[\033[00m\]:\[\033[1;35m\]\w\[\033[00m\]\$ ‘

mentre Neon ha questa:

PS1=’\[\033[0;36m\]\u\[\033[1;00m\]@\[\033[1;32m\]\h\[\033[1;00m\]:\[\033[1;35m\]\w\[\033[1;00m\]\$ ‘

Aggiungo il link ad un’utile guida di debianizzati.org: Colorare bash.

Ho avuto modo di vedere una semplice fork bomb all’opera.

Mi sembrava una cosa curiosa, e pensavo di scriverci un post… Poi ho aperto wikipedia… E vabbè. Qui c’è già tutto. :)

Fatto sta, che è meglio non scrivere

 :( ){:|:&};:

in console.

    
SIMOTRONE WEB PAGE is based on WordPress platform, RSS tech , RSS comments design by Gx3.