%From mau@beatles.cselt.stet.it Mon Jan 10 08:48:23 1994
%Date: Mon, 10 Jan 1994 10:14:49 +0100
%From: Maurizio Codogno <mau@beatles.cselt.stet.it>
%Subject: Much behind
%To: greenfie@gauss.rutgers.edu
%X-Envelope-To: greenfie@gauss.rutgers.edu
%Content-Transfer-Encoding: 8BIT
%
%At the moment I only completed sections about find(1) and dd(1). I'm
%attaching them below, because I'd like to know whether my approach to
%the presentation is satisfactory...
%
%ciao, .mau.
%
%=======================
%
%testi
\chapter{Comandi buffi}\label{funny-chapter}

Beh, la maggior parte di chi ha avuto a che fare con i comandi UNIX trattati in
questo capitolo non sar\`a d'accordo con questo titolo. ``Che diamine! Mi hai
appena fatto vedere che l'interfaccia di Linux \`e standard, e adesso abbiamo un
sacco di comandi, ognuno che lavora in modo completamente diverso. Non mi
ricorder\`o mai tutte queste opzioni, e mi stai dicendo che sono {\em buffi}?''
Ebbene s\`{\i}, ecco un esempio di senso dell'umorismo degli hackers. Comunque,
guardate il lato positivo: non esiste un equivalente MS-DOS di questi comandi; se
ne avete bisogno, li dovete comprare, e non saprete mai come sar\`a la loro
interfaccia. Ecco un'utile -- e gratuita -- aggiunta, quindi divertitevi!

L'insieme di comandi coperto in questo capitolo comprende {\tt find}, che
permette all'utente di cercare nell'albero delle directory dei gruppi specifici
di file, {\tt tar}, utile per creare degli archivi da spedire o da salvare, {\tt
dd}, il copiatore a basso livello, e {\tt sort}, che \ldots s\`{\i}, ordina i file.
Un'ultimo commento; questi comandi non sono affatto standardizzati, e, anche se
troverete delle opzioni comuni a tutti i sistemi $*$IX, la versione GNU, che \`e
quella spiegata qui e che troverete su tutti i sistemi Linux, ha di solito molte
capacit\`a aggiuntive. Quindi, se progettate di usare altri sistemi operativi di
tipo UNIX, non dimenticate di controllare la pagina man del sistema in
questione per imparare le differenze, che spesso non sono trascurabili.

\section{{\tt find}, per cercare i file}

\subsection{Generalit\`a}

Tra i vari comandi visti finora, ce ne sono alcuni che permettono all'utente di
scendere ricorsivamente nell'albero delle directory per fare qualche azione: gli
esempi canonici sono {\tt ls -R} e {\tt rm -R}. Bene. {\tt find} \`e {\em il\/}
comando ricorsivo. Ogni volta che pensate ``Beh, devo fare questo e quest'altro
su tutti questi tipi di file nella mia partizione'', dovreste pensare di usare
{\tt find}. In un certo senso il fatto che {\tt find} trovi file \`e un effetto
secondario: il suo vero compito \`e valutare.

La struttura di base del comando \`e la seguente:

\begin{command}
{\tt find}\impttindex{find} {\em percorso} [\ldots] {\em espressione} [\ldots]
\end{command}

Questo almeno vale per la versione GNU; altre versioni non permettono di
specificare pi\`u di un percorso, ed inoltre \`e molto raro che serva una cosa del
genere. La spiegazione della sintassi del comando \`e piuttosto semplice: dite da
dove volete che cominci la ricerca (la parte {\em percorso\/}; con GNU si pu\`o
omettere e per default verr\`a presa in considerazione la directory corrente {\tt
.}), e che tipo di ricerca volete fare (la parte {\em espressione\/}).


Il comportamento standard del comando \`e piuttosto complicato, quindi vale la pena
notarlo. Supponiamo che nella vostra home directory ci sia una directory {\tt butta},
che contiene il file {\tt pippo}. Digitate {\tt find .\ -name pippo} (che come potete
indovinare ricerca un file di nome {\tt pippo}), e ottenete \ldots niente altro che il
prompt. Il problema sta nel fatto che {\tt find} \`e per default silenzioso: rende 0
se la ricerca \`e stata completata (trovando qualcosa o meno) o un valore non-zero
se ci sono stati dei problemi. Questo non accade con la versione che trovate su
Linux, ma \`e comunque utile da ricordare. 

\subsection{Espressioni}

La parte delle {\em espressioni\/} pu\`o essere divisa in quattro gruppi di parole
chiave diversi: {\em opzioni}, {\em test}, {\em azioni\/} ed
{\em operatori\/}; ognuno
di questi pu\`o restituire un valore vero o falso, insieme ad un effetto
secondario.
Le differenze tra i gruppi vengono mostrate pi\`u avanti.

\begin{description}

\item [opzioni] influiscono sulle operazioni generali di find, piuttosto che sul
processo di un singolo file. Un esempio \`e {\sf -follow}, che dice a {\tt find} di
seguire i link simbolici invece di dire semplicemente l'inode. Restituisce
sempre il valore vero.

\item [test] sono veri e propri controlli (ad esempio, {\sf -empty} controlla se il file
\`e
vuoto), e possono restituire i valori vero o falso.

\item [azioni] hanno anche un effetto secondario, il nome del file considerato.
Possono restituire vero o falso anch'esse.

\item [operatori] non restituiscono un valore (possono essere considerati veri
per convenzione), e vengono usati per costruire espressioni compresse. Un esempio
\`e {\sf -or}, che prende l'O logico delle due sottoespressioni ai suoi lati.
Notate che quando si mettono due espressioni una dopo l'altra, \`e sottinteso
{\sf -and}. 

\end{description}

Notate che {\tt find} si basa sulla shell per leggere la linea di comando, ci\`o
significa che le parole chiave devono essere messe tra spazi, e soprattutto che
molti caratteri devono essere trattati in modo da non essere corrotti dalla
shell. Si pu\`o fare sia con la barra rovesciata che con le virgolette, singole e
doppie; negli esempi le parole chiave a carattere singolo verranno quotate con la
barra rovesciata, perch\'e (almeno secondo me, ma sono io che scrivo queste note!)
\`e il modo pi\`u semplice. 

\subsection{Opzioni}

Ecco la lista di tutte le opzioni note alla versione GNU di {\tt find}. 
Ricordate che restituiscono sempre il valore vero.

\begin{itemize}

\item {\sf -daystart} misura il tempo trascorso non da 24 ore fa ma dalla
scorsa mezzanotte. Un vero hacker probabilmente non capir\`a l'utilit\`a
di questa opzione, ma un programmatore che lavora dalle otto alle cinque
l'apprezzer\`a di sicuro.

\item {\sf -depth} processa il contenuto di ciascuna directory prima della
directory stessa. Per dire la verit\`a, non conosco molti usi di questa
opzione, tranne che per un'emulazione del comando {\tt rm -F}
(naturalmente non potete cancellare una directory prima di aver cancellato
tutti i file in essa contenuti \ldots).

\item {\sf -follow} dereferenzia (cio\`e, segue) i link simbolici. Implica
l'opzione -noleaf; vedi sotto).

\item {\sf -noleaf} toglie un'ottimizzazione che dice ``Una directory
contiene due sottodirectory di meno del loro conteggio degli hard link''.
Se il mondo fosse perfetto, tutte le directory sarebbero referenziate da
ognuna delle loro sottodirectory (grazie all'opzione {\tt ..}), come
{\tt .} dentro se stessa, e dal suo nome ``reale'' dalla sua directory
madre.

Ci\`o significa che ciascuna directory deve essere referenziata almeno due
volte (una da se stessa, una dalla sua madre) e ogni referenza aggiuntiva
proviene da una sottodirectory. In pratica, comunque, i link simbolici ed
i filesystem distribuiti\footnote{I filesystem distribuiti permettono ai
file di apparire come locali su una macchina mentre sono in realt\`a da
qualche altra parte.} possono rompere questa regola. Questa opzione fa
girare {\tt find} leggermente pi\'u lento, ma pu\`o dare i risultati
attesi.

\item {\sf -maxdepth {\it livelli}}, {\sf -mindepth {\it livelli}},
dove {\it livelli} \`e un intero non negativo, che indica rispettivamente
il numero massimo e minimo di livelli di directory in cui cercare. Sono
obbligatori un paio di esempi:
{\tt -maxdepth 0} indica che il comando deve essere applicato solo agli
argomenti nella linea di comando, cio\`e senza entrare ricorsivamente
nell'albero delle directory;
{\tt -mindepth 1} inibisce l'applicazione del comando agli argomenti nella
linea di comando, mentre vengono processati tutti gli altri file pi\'u in
basso nell'albero.

\item {\sf -version} stampa semplicemente il numero di versione corrente
del programma.

\item {\sf -xdev}, che \`e un nome che trae in inganno, dice a 
{\tt find} di {\bf non} incrociare i dispositivi, cio\`e di non cambiare
filesystem. \`E molto utile quando si sta cercando qualcosa nel filesystem
di root; in molte macchine \`e una partizione piuttosto piccola, ma un
{\tt find} normale cercherebbe in tutta la struttura!

\end{itemize}

\subsection{Test}

I primi due test sono molto semplici da capire: {\sf -false} restituisce
solo il valore falso, mentre {\sf -true} restituisce solo il valore vero.
Altri test che non hanno bisogno della specifica di un valore sono {\sf
-empty}, che restituisce il valore vero se il file \`e vuoto, e la coppia
{\sf -nouser} / {\sf -nogroup}, che restituiscono il valore vero se
nessuna voce di {\tt /etc/passwd} o {\tt /etc/group} corrisponde all'id di
utente/gruppo del proprietario del file; \`e una cosa comune che
accade nei sistemi multiutente: viene cancellato un utente, ma nei posti
pi\`u strani del filesystem restano suoi file, e per la legge di Murphy
occupano un sacco di posto.

Naturalmente, \`e possibile ricercare un utente o un gruppo specifico. I
test sono {\sf -uid {\sl nn}} e {\sf -gid {\sl nn}}. Sfortunatamente non
\`e possibile dare direttamente il nome dell'utente, ma bisogna usare l'id
numerico, {\em nn}. 

\`E possibile usare le forme $+nn$, che sta per ``un valore strettamente
maggiore di {\em nn\/}'' e $-nn$, che sta per ``un valore strettamente
minore di {\em nn\/}'';
\`e piuttosto stupido nel caso degli
UID, ma sar\`a comodo con altri test.

Un'altra opzione utile \`e {\sf -type {\em c}}, che restituisce il
valore vero se il file \`e di tipo {\em c}.
Le corrispondenze mnemoniche per le scelte possibile sono le stesse che in
{\tt ls}; quindi si ha {\bf b} per i file block special, {\bf c} per
quelli character special, {\bf d} per le directory, {\bf p} per le pipe
con nome, {\bf l} per i link simbolici, e {\bf s} per le socket. I file
regolari sono indicati con una {\bf f}. Un test correlato \`e {\sf
-xtype}, che \`e simile a -type tranne nel caso dei link simbolici. Se non
\`e stato dato -follow, il file a cui si punta viene controllato al posto
del link stesso. Completamente scorrelato \`e il test {\sf -fstype {\em
tipo\/}}; in questo caso viene controllato il filesystem. Credo di aver
preso questa informazione dal file {\tt /etc/mtab}, quello che indica i
filesystem che vengono montati; sono sicuro che i tipi nfs, tmp, msdos ed
ext2 vengono riconosciuti.

I test {\sf -inum {\em nn\/}} e {\sf -links {\em nn\/}} controllano se il
file ha numero di inode {\em nn\/} o {\em nn\/} link, mentre {\sf -size
{\em nn\/}} rende vero se il file ha allocato {\em nn\/} blocchi da 512
byte (beh, non precisamente: per i file sparsi i blocchi non allocati
vengono contati lo stesso). Dato che al giorno d'oggi i risultati di {\tt
ls -s} non vengono sempre misurati in parti da 512 byte (Linux per esempio
usa unit\`a di 1K), \`e possibile appendere a {\em nn\/} il carattere $b$
per contare in byte, o $k$ per contare in kilobyte.

I bit di permesso vengono controllati con il test {\sf -perm {\em modalit\`a}}.
Se
{\em modalit\`a\/} non ha segno, i bit di permesso dei file devono combaciare
perfettamente. Un $-$ che precede i bit significa che tutti i bit di permesso
devono essere impostati, ma non fa assunzioni sugli altri; un $+$ \`e soddisfatto
se uno qualsiasi dei bit \`e impostato. Ops! Mi dimenticavo di dire che la modalit\`a
\`e scritta in ottale o simbolicamente, come si fa in {\tt chmod}.

Il prossimo gruppo di test \`e correlato all'ora di ultimo utilizzo del file; \`e
comodo quando un utente ha riempito il suo spazio, e come al solito ci sono
moltissimi file inutilizzati da anni, e di cui si \`e dimenticato il significato. 
Il problema \`e trovarli, e {\tt find} \`e l'unica speranza. {\sf -atime {\em nn\/}}
rende vero se il file \`e stato utilizzato {\em nn\/} giorni fa -- ad esempio, con un
comando {\tt chmod} -- e {\sf -mtime {\em nn\/}} se il file \`e stato modificato
per l'ultima volta {\em nn\/} giorni fa. Talvolta si ha bisogno di un tempo pi\`u
preciso; il test {\sf newer {\em file\/}} \`e soddisfatto se il file considerato \`e
stato modificato dopo {\em file}. Quindi, dovete semplicemente usare {\tt
touch} con la data desiderata, ed avete fatto. Il find della GNU aggiunge i test
{\sf -anewer} e {\sf -cnewer} che si comportano in maniera simile, ed i test  
{\sf -amin}, {\sf -cmin} e {\sf -mmin}, che contano il tempo in minuti invece che
in periodi di 24 ore.

Per ultimo, il test che uso pi\`u spesso: {\sf -name {\em pattern\/}} rende vero se
il nome del file corrisponde esattamente a {\em pattern}, che \`e pi\`u o meno
quello che si usa in un {\tt ls} standard. Perch\'e `pi\`u o meno'? Perch\'e
naturalmente dovete ricordare che tutti i parametri sono processati dalla shell,
e quei bei metacaratteri vengono espansi. Quindi, un test come {\tt -name foo*}
non render\`a quello che volete, e dovreste scrivere o {\tt -name foo\*} o {\tt
-name "foo*"}. Questo \`e probabilmente uno degli errori pi\`u comuni fatti dagli
utenti disattenti, quindi scrivetelo a lettere GRANDI sul vostro schermo.  
Un altro problema \`e che, come con {\tt ls}, i punti all'inizio non vengono
riconosciuti; per questo potete usare il test {\sf -path {\em pattern}}, che
non si preoccupa dei punti e delle barre quando paragona il percorso del file
considerato con {\em pattern}.

\subsection{Azioni}

Ho detto che le azioni fanno, appunto, un'azione. Beh, {\sf -prune} invece non fa
qualcosa, cio\`e non discende all'interno dell'albero delle directory (a meno che
non si dia -depth). Di solito si trova insieme a -fstype, per scegliere tra i
vari filesystem da controllare.

Le altre azioni possono essere divise in due grandi categorie:

\begin{itemize}

\item Azioni che {\em stampano\/} qualcosa. La pi\`u banale -- e certo, l'azione di
default di {\tt find} -- \`e {\sf -print} che stampa semplicemente il nome del/dei
file che corrispondono alle altre condizioni nella linea di comando, e rende il
valore vero. Una semplice variante di -print \`e {\sf -fprint {\em file}}, che
usa {\em file\/} invece dell'output standard, {\sf -ls} elenca il file corrente
nello stesso formato di {\tt ls -dils}, {\sf -printf {\em formato\/}} si comporta
pi\`u o meno come la funzione del C printf(), in modo che potete specificare come
formattare l'output, e  {\sf -fprintf {\em file formato\/}} fa la stessa cosa, ma
scrivendo su {\em file}. Anche queste azioni rendono il valore vero.

\item Azioni che {\em eseguono\/} qualcosa. La loro sintassi \`e un po' strana e
sono largamente usate, quindi per favore dategli un'occhiata.

{\sf -exec {\em comando\/} \verb-\;-} il comando \`e eseguito, e l'azione
restituisce il valore vero se il suo stato finale \`e 0, cio\`e se l'esecuzione \`e
regolare. La ragione per il {\tt \verb-\;-} \`e piuttosto logica: {\tt find} non sa
dove finisce il comando, e il trucco di mettere l'azione exec alla fine del
comando non \`e applicabile. Beh, il modo migliore per segnalare la fine del
comando \`e di usare il carattere che la shell stessa usa, cio\`e
`{\tt ;}', ma naturalmente un punto e virgola da solo sarebbe mangiato dalla
shell e non arriverebbe a {\tt find}, quindi deve essere usato con un comando di 
escape. La seconda cosa
da ricordare \`e come specificare il nome del fie corrente all'interno di {\em
comando}, dato che probabilmente vi siete adoperati perch\'e l'espressione faccia
qualcosa, e non solo stampare {\tt date}; si fa per mezzo della stringa
\verb-{}-. Alcune versioni vecchie di {\tt find} richiedono che debba essere
messa tra spazi bianchi -- non molto comodo se ad esempio vi serve il percorso
intero e non solo il nome del file -- ma con il find della GNU pu\`o essere ovunque
nella stringa che compone {\em comando}. E, chiederete di sicuro, non deve essere 
 usato con un comando di escape o quotato? Meraviglioso: non l'ho mai dovuto fare
n\'e sotto tcsh n\'e sotto bash (sh non considera 
\verb-{- e
\verb-}- come caratteri speciali, quindi non \`e un problema). La mia idea \`e che la
shell ``sa''  che \verb-{}- non \`e un'opzione che ha senso, quindi non prova ad
espanderla, fortunatamente per {\tt find}, che la ottiene integra.

{\sf -ok {\em comando\/} \verb-\;-} si comporta come -exec, con la differenza che
per ogni file scelto viene chiesto all'utente di confermare il comando; se la
risposta inizia per {\tt y} o {\tt Y} viene eseguito, altrimenti no, e l'azione
restituisce il valore falso.

\end{itemize}

\subsection{Operatori}

Esistono numerosi operatori: eccone una lista, in ordine di precedenza
decrescente.

\begin{description}

\item[{\sf $\backslash$( {\em espr\/} $\backslash$)}]
~\vspace{-\itemsep}\vspace{-\itemsep}
\item[~]
forza l'ordine precedente. Le parentesi devono naturalmente essere quotate, dato
che hanno un significato anche per la shell.

\item[{\sf ! {\em espr\/}}]
~\vspace{-\itemsep}\vspace{-\itemsep}
\item[{\sf -not {\em espr\/}}] 
~\vspace{-\itemsep}\vspace{-\itemsep}
\item[~]
cambia il valore vero/falso dell'espressione, cio\`e se  {\em espr\/} \`e vero
diventa falso. Il punto esclamativo non ha bisogno di un carattere di escape,
dato che \`e seguito da uno spazio.

\item[{\sf {\em espr1 espr2} }]
~\vspace{-\itemsep}\vspace{-\itemsep}
\item[{\sf {\em espr1\/} -a {\em espr2\/} }]
~\vspace{-\itemsep}\vspace{-\itemsep}
\item[{\sf {\em espr1\/} -and {\em espr2\/} }] 
~\vspace{-\itemsep}\vspace{-\itemsep}
\item[~] corrispondono tutti all'operazione logica E, che \`e implicita nel primo e
nel secondo caso. 
{\em espr2\/} non viene valutata, se {\em espr1\/} \`e falsa.

\item[{\sf {\em espr1\/} -o {\em espr2\/} }]
~\vspace{-\itemsep}\vspace{-\itemsep}
\item[{\sf {\em espr1\/} -or {\em espr2\/} }] 
~\vspace{-\itemsep}\vspace{-\itemsep}
\item[~] corrisponde all'operazione logica O. 
{\em espr2\/} non viene valutata, se
{\em espr1\/} \`e vera.

\item[{\sf {\em espr1\/} , {\em espr2\/} }] 
~\vspace{-\itemsep}\vspace{-\itemsep}
\item[~] \`e l'indicazione dell'elenco; vengono valutate sia 
{\em espr1\/} che {\em espr2}, (e naturalmente anche tutti gli effetti
secondari!) ed il valore finale dell'espressione \`e quello di 
{\em espr2}.

\end{description}

\subsection{Esempi}

Beh s\`{\i}, {\tt find} ha proprio troppe opzioni, lo so, ma ci sono un sacco di modi
predefiniti di usarlo che vale la pena ricordare, dato che vengono usati molto
spesso. Vediamone alcuni.

\begin{verbatim}
% find . -name foo\* -print
\end{verbatim}
trova tutti i nomi di file che cominciano per {\tt foo}. Se la stringa pu\`o
trovarsi all'interno del nome, probabilmente \`e pi\`u indicato scrivere {\tt
"*foo*"} invece di {\tt \*foo\*}.

\begin{verbatim}
% find /usr/include -xtype f -exec grep foobar \
           /dev/null {} \;
\end{verbatim}
\`e un grep eseguito ricorsivamente a partire dalla directory /usr/include. In
questo caso ci interessano sia il file regolare che i link simbolici che puntano
a file regolari, da cui il test -xtype. Molte volte \`e pi\`u semplice evitare di
specificarlo, specialmente se siamo piuttosto sicuri che non esistono file binary
che contengono la stringa desiderata. E perch\'e il /dev/null nel comando? \`E un
trucco per forzare grep a scrivere il nome del file dove trova una
corrispondenza. Il comando grep viene applicato a ciascun file in un'invocazione
diversa, e quindi non pensa che sia necessario di dare come output il nome del
file; ma ora ci sono {\em due\/} file, cio\`e il file corrente e {\tt /dev/null}!
Un'altra possibilit\`a \`e fare una pipe del comando verso {\tt xargs} e fargli fare
il grep. L'ho appena provato ed ho distrutto del tutto il mio filesystem (anche
queste note che sto cercando di recuperare a mano {\tt :-(} ).

\begin{verbatim}
% find /  -atime +1 -fstype ext2 -name core \
              -exec rm {} \;
\end{verbatim}
\`e un tipico lavoro da crontab: cancella tutti i file {\tt core} nei filesystem di
tipo ext2 che non hanno avuto accessi nelle ultime 24 ore. \`E possibile che
qualcuno voglia usare il file core per fare un dump post mortem, ma nessuno si
pu\`o ricordare quello che stava facendo 24 ore prima\ldots

\begin{verbatim}
% find /home -xdev -size +500k -ls > piggies
\end{verbatim}
\`e utile sapere chi ha questi file che intasano il filesystem. Notate l'uso di
-xdev: dato che ci interessa un solo filesystem, non \`e necesario scendere negli
altri montati sotto {\tt /home}.

\subsection{Un'ultima parola}

Tenete a mente che {\tt find} \`e un comando che prende moltissimo tempo, dato che
deve accedere a tutti gli inode del sistema per operare. \`E quindi saggio
combinare tutte le operazioni che vi servono in un'unica invocazione di
{\tt find}, specialmente nei lavori di `pulizia' fatti da crontab. Un
esempio illuminante \`e questo: supponiamo di voler cancellare i file che
finiscono con {\tt .BAK} e cambiare le protezioni di tutte le directory a
771 e quelle dei file che finiscono con {\tt .sh} a 755. E magari stiamo
montando dei filesystem via NFS su un collegamento via modem, e non
vogliamo controllare quei file. Perch\'e scrivere tre comandi separati? Il
modo pi\`u efficace di portare a termine il compito \`e questo:

\begin{verbatim}
% find . \( -fstype nfs -prune \) -o \
         \( -type d       -a -exec chmod 771 {} \; \) -o \
         \( -name "*.BAK" -a -exec /bin/rm {}   \; \) -o \
         \( -name "*.sh"  -a -exec chmod 755 {} \; \) 
\end{verbatim}

Sembra brutto (e che spreco di barre rovesciate!), ma guardando
attentamente rivela che la logica che c'\`e sotto \`e molto lineare. Ricordate
che quello che fa in realt\`a \`e una valutazione vero/falso; il comando
compreso \`e solo un effetto secondario. Ma ci\`o significa che viene fatto
solo se {\tt find} deve valutare la parte exec dell'espressione, cio\`e solo
se il lato sinistro della sottoespressione rende vero. Quindi, se per
esempio il file considerato al momento \`e una directory viene valutato il
primo exec ed i permessi dell'inode vengono cambiati a 771; altrimenti se
ne dimentica e passa alla seconda sottoespressione. Probabilmente \`e pi\`u
semplice vederlo in pratica che scriverlo, ma dopo un po' diventer\`a una
cosa naturale. 

\section{{\tt tar}, l'archiviatore a nastro}

\subsection{Introduzione}

\subsection{Le opzioni principali}

\subsection{Modificatori}

\subsection{Esempi}

\section{{\tt dd}, il duplicatore di dati}

La leggenda narra che all'inizio dei tempi, quando fu creato il primo UNIX, i
suoi sviluppatori avevano bisogno di un comando a basso livello per copiare i
dati tra dispositivi. Dato che avevano molta fretta, decisero di prendere in
prestito la sintassi usata dalle macchine IBM-360, e di sviluppare in seguito
un'interfaccia consistente con quella degli altri comandi. Il tempo pass\`o, e
tutti si erano talmente abituati allo strano modo di usare il comando {\tt dd}
che rimase com'era. Non so se \`e vero, ma \`e una bella storia.

\subsection{Opzioni}

A dire la verit\`a, {\tt dd} non \`e proprio diverso dagli altri comandi Unix: \`e un
{\bf filtro}, che legge per default dall'input standard e scrive sull'output
standard. Cos\`{\i}, se digitate semplicemente dd al terminale, resta in silenzio
aspettando dell'input, e ctrl-C \`e l'unica cosa sensata da digitare.

La sintassi del comando \`e la seguente:

\vspace{1ex}
\begin{command}
  {\tt dd}\impttindex{dd} [if={\sl file}] [of={\sl file}] [ibs={\sl
    byte}] [obs={\sl byte}] [bs={\sl byte}] [cbs={\sl byte}]
  [skip={\sl blocchi}]\\
  \hspace{.5in} [seek={\sl blocchi}] [count={\sl blocchi}]
  [conv=\{ascii, ebcdic, ibm, block, unblock,\\
  \hspace{.5in} lcase, ucase, swab, noerror, notrunc, sync\}]
\end{command}

Tutte le opzioni hanno la forma {\em opzione$=$valore}. Non sono permessi spazi
n\'e prima n\'e dopo il segno di uguale; disturbava, dato che la shell in una
situazione del genere non espandeva
un nome di file, quindi non ve ne dovete preoccupare. \`E anche importante
riordare che tutti i valori sotto forma di numeri 
({\tt byte} e {\tt blocchi} qui sopra) possono essere seguiti da un
moltiplicatore. Le possibili scelte sono {\bf b} per blocchi, che moltiplica per
512, {\bf k} per kilobyte (1024), {\bf w} per parole (2) e {\tt x}{\bf m}
moltiplica per {\bf m}.

La spiegazione delle opzioni \`e data qui sotto.

\begin{itemize}

\item {\sf if={\em filein\/}} e {\sf of={\em fileout\/}} dicono a 
{\tt dd} rispettivamente di leggere da {\em filein\/} e scrivere su  {\em
fileout}. Nell'ultimo caso, il file di output viene troncato al valore dato a
{\tt seek}, o, se la parola chiave non \`e presente, a 0 (cio\`e viene cancellato),
prima di fare l'operazione. Ma date un'occhiata all'opzione {\tt notrunc}.

\item {\sf ibs={\em nn\/}} e {\sf obs={\em nn\/}} specificano quanti byte devono
essere letti o scritti alla volta. Credo che il default sia 1 blocco, cio\`e 512
byte, ma non ne sono molto sicuro: quello che \`e sicuro \`e che funziona in quel
modo con i file semplici. Questi parametri sono molto importanti quando si usano
device speciali come input o output; ad esempio, leggere dalla rete dovrebbe
impostare {\tt ibs} a 10k, mentre un floppy da 3.5'' ad alta densit\`a ha la sua
naturale grandezza di blocchi a 18k. Non impostare questi valori pu\`o non solo
aumentare il tempo di compimento del comando, ma anche portare ad errori di
timeout, quindi state attenti.

\item {\sf bs={\em nn\/}} legge e scrive 
{\em nn\/} byte alla volta. Supera le parole chiave 
{\tt ibs} e {\tt obs}.

\item {\sf cbs={\em nn\/}} imposta i buffer di conversione a 
{\em nn\/}
byte. Questi buffer vengono usati quando si traduce da ASCII a EBCDIC o da 
un dispositivo senza blocchi ad uno che li ha. Ad esempio, i file creati sotto
VMS hanno spesso blocchi di 512 byte, cosicch\'e bisogna impostare {\tt cbs} a 1b
quando si legge un nastro VMS\@. Spero che non dobbiate mai lottare con questo tipo
di cose!

\item {\sf skip={\em nbl\/}} e {\sf seek={\em nbl\/}} dicono al programma di
saltare {\em nbl\/} blocchi rispettivamente all'inizio dell'input ed all'inizio
dell'output. Naturalmente il secondo caso ha senso se si d\`a la conversione 
{\tt notrunc} (vedere sotto). Le dimensioni di ogni blocco sono il valore di {\tt
ibs} ({\tt obs}). Attenzione: se non avete impostato {\tt ibs} e scrivete {\tt
skip=1b} state in realt\`a saltando 512$\times$512 byte, cio\`e 256KB\@. Non \`e
precisamente quello che volevate, no?

\item {\sf count={\em nbl\/}} copia solo {\em nbl\/} blocchi dall'input, ognuno
delle dimensioni date da {\tt ibs}. Questa opzione, insieme alla precedente,
rimane utile se per esempio avete un file corrotto e volete recuperarne il pi\`u
possibile: saltate le parti illeggibili e prendete quello che resta.

\item {\sf conv={\em conversione},[{\em conversione}\ldots]} converte il file
come specificato dall'argomento. Le conversioni possibili sono {\sf ascii}, che
converte da EBCDIC ad ASCII, {\sf ebcdic} e {\tt ibm}, che fanno entrambe una
conversione inversa (s\`{\i}, non c'\`e un'unica conversione da EBCDIC ad ASCII\@! La
prima \`e quella standard, ma la seconda funziona meglio se dovete stampare i file
su una stampante IBM), {\sf block}, che porta linee che finiscono con un
carattere di newline alla lunghezza di {\tt cbs}, sostituendo la newline con
degli spazi, {\sf unblock}, che fa l'opposto (elimina gli spazi in fondo alla
linea, e li sostituisce con un carattere di newline), {\sf lcase} e {\sf ucase},
per convertire il testo da maiuscole a minuscole e viceversa, {\sf swab}, che
scambia ogni coppia di byte di input (ad esempio ne avete bisogno per usare un
file contenente degli interi corti scritto su una macchina 680x0 con una macchina
Intel), {\sf noerror}, per continuare ad agire su un file anche dopo aver
incontrato errori, e {\sf sync}, che porta i blocchi di input alla dimensione di
{\tt ibs} aggiungendo dei caratteri NUL alla fine.

\end{itemize}

\subsection{Esempi}

L'esempio classico \`e quello in cui siete incappati quando avete provato a creare
il primo dischetto Linux: come scrivere su un floppy senza un
filesystem MS-DOS\@.
La soluzione \`e semplice:
\begin{verbatim}
% dd if=disk.img of=/dev/fd0 obs=18k count=80
\end{verbatim}
Ho deciso di non usare 
{\tt ibs} perch\'e non so qual'\`e la grandezza di blocchi migliore per un hard disk,
ma in questo caso non avrei fatto nessun danno se al posto di {\tt obs} avessi
usato {\tt bs} -- potrebbe anche essere stato leggermente pi\`u veloce. Notate
l'esplicitazione del numero di settori da scrivere (18KB vengono occupati da un
settore, quindi {\tt count} viene impostato a 80) e l'uso del nome a basso
livello del dispositivo floppy.

Un'altra applicazione utile di {\tt dd} \`e legata al backup su rete. Supponiamo
di essere sulla macchina {\sl alfa}, e che sulla macchina {\sl beta\/} ci sia
l'unit\`a a nastro {\tt /dev/rst0}, con un file tar che ci interessa prendere.
Abbiamo gli stessi privilegi su entrambe le macchine, ma non c'\`e spazio su {\sl
beta\/} per mettere il file tar. In questo caso, possiamo scrivere
\begin{verbatim}
% rsh beta 'dd if=/dev/rst0 ibs=8k obs=20k' | tar xvBf - 
\end{verbatim}
per fare l'intera operazione in un solo passo. In questo caso, abbiamo usato le
possibilit\`a date da {\tt rsh} di leggere dal nastro. Le dimensioni di input ed
output sono impostate al default per questa operazione, cio\`e 8KB per leggere dal
nastro e 20KB per scrivere sulla ethernet; dal punto di vista dell'altro estremo
del tar, c'\`e lo stesso flusso di byte che si pu\`o prendere dal nastro, eccetto per
il fatto che arriva in maniera non costante, ed \`e necessaria l'opzione B.

Dimenticavo: non credo proprio che {\tt dd} sia un acronimo per ``duplicatore
dati'', ma almeno \`e un buon modo per ricordarsi il suo significato\ldots

\section{{\tt sort}, per ordinare i dati}

\subsection{Introduzione}

\subsection{Opzioni}

\subsection{Esempi}


