Archiviare il contenuto di una cartella con tar

Screen Shot 2014-03-01 at 19.44.03

Il comando tar è stato studiato per essere semplice ed immediato. Archiviare una cartella, che contiene file nascosti e file con degli spazi nel nome, è quanto mai banale: 

it7002@it07pc202:~$ mkdir pippo
it7002@it07pc202:~$ touch pippo/primo
it7002@it07pc202:~$ touch pippo/.secondo
it7002@it07pc202:~$ touch pippo/e\ terzo
it7002@it07pc202:~$ tar -cf archivio0.tar pippo
it7002@it07pc202:~$ tar -tf archivio0.tar
pippo/
pippo/.secondo
pippo/e terzo
pippo/primo
it7002@it07pc202:~$

Ma come fare se si vuole inserire nell’archivio solo i contenuti, ma non la cartella stessa? Una prima soluzione consiste nell’usare l’opzione ‘-C’ di tar, che indica a tar quale directory usare come riferimento, e chiedergli di archiviare proprio quella (la directory corrente, indicata da ‘.’):

it7002@it07pc202:~$ tar -C pippo -cf archivio1.tar .
it7002@it07pc202:~$ tar -tf archivio1.tar
./
./.secondo
./e terzo
./primo
it7002@it07pc202:~$

Il risultato è già ottimo e pari a quello voluto; ma rimane l’inestetismo di avere nell’archivio generato i nomi nella forma ‘./*’, e la cartella superflua ‘./’.

Per quelli, come me, che sono dei pignoli inguaribili, ecco una soluzione un po’ contorta, ma perfetta fino all’ultimo bit:

it7002@it07pc202:~$ IFS_ORIGINALE="$IFS"
it7002@it07pc202:~$ IFS=$'\n'
it7002@it07pc202:~$ tar -C pippo -cf archivio2.tar $( ls -a pippo | grep -v '\(^\.$\)\|\(^\.\.$\)' )
it7002@it07pc202:~$ IFS="$IFS_ORIGINALE"
it7002@it07pc202:~$ unset IFS_ORIGINALE
it7002@it07pc202:~$ tar -tf archivio2.tar
e terzo
primo
.secondo
it7002@it07pc202:~$

Siccome è effettivamente un po’ complicato, meglio spiegarlo riga per riga.

Nella prima riga si salva il valore originale di una variabile di shell che sarà modificata in seguito, in modo da poterla ripristinare al termine della procedura.

La seconda riga modifica la variabile IFS (Internal Fields Separator). Questa variabile definisce i caratteri che la shell Bash utilizza per separare tra di loro i campi in svariati contesti. Di default vale $’ \t\n’, che sta per ‘spazio’, ‘tabulazione orizzontale’ e ‘new line’. Ma in questo contesto trattare il carattere spazio come un separatore non va bene, perché si vogliono processare anche i file con uno spazio nel nome. Quindi si modifica la variabile IFS in modo che ci sia un unico separatore: il carattere ‘new line’ (\n). La differenza pratica, per l’esempio in oggetto, è che il nome ‘e terzo’ viene considerato come un unico file, invece che come due file di nome ‘e’ e ‘terzo’.

Nella terza riga si fa il lavoro sporco: il comando tar usa come riferimento la directory pippo (opzione -C), crea nella cartella corrente l’archivio archivio2.tar e pone al suo interno i file indicati dal comando contenuto tra “$(” e “)”. Questo è un costrutto della shell Bash molto utile, che serve ad inserire nel contesto in cui viene valutato l’output prodotto da un determinato comando, piuttosto che il comando stesso. Per capirsi, nell’esempio che segue la variabile ADESSO andrà a contenere l’output del comando date, non la stringa “$( date )”:

it7002@it07pc202:~$ ADESSO=$( date )
it7002@it07pc202:~$ echo $ADESSO
gio feb 27 14:23:42 CET 2014
it7002@it07pc202:~$

In questo caso il comando è “ls -a pippo | grep -v ‘\(^\.$\)\|\(^\.\.$\)'”, e il suo output è, come vedremo tra breve, l’elenco di tutti i file contenuti nella directory pippo, esclusi i file ‘.’ (la directory corrente) e ‘..’ (la directory padre della directory corrente). Questo effetto è ottenuto filtrando – tramite pipe (‘|’) – l’output del comando ‘ls -a pippo’ (l’elenco di tutti i file e le directory contenuti nella directory pippo, anche quelli nascosti) con il comando grep. Come pattern del comando grep si usa una espressione regolare verificata solo dalle stringhe ‘.’ e ‘..’ (‘\(^\.$\)\|\(^\.\.$\)’), congiuntamente  all’opzione ‘-v’, che ha come effetto quello di invertire la logica del comando (visualizza tutte le linee che non corrispondono al pattern indicato).

La quarta e quinta riga ripristinano semplicemente le variabili di ambiente come erano all’inizio.

Come si vede, anche fare una cosa semplice come un archivio con tutti i contenuti di una cartella, ma non la cartella stessa, richiede la conoscenza di alcune nozioni, nonché l’uso di alcune tecniche, non alla portata di un principiante della shell Bash. Questa è uno strumento estremamente potente, e consente di automatizzare moltissimi tra i compiti del tipico workload dell’amministratore di sistema Unix. A patto, però, di prenderci un po’ di confidenza.

Advertisements

Rispondi

Inserisci i tuoi dati qui sotto o clicca su un'icona per effettuare l'accesso:

Logo WordPress.com

Stai commentando usando il tuo account WordPress.com. Chiudi sessione / Modifica )

Foto Twitter

Stai commentando usando il tuo account Twitter. Chiudi sessione / Modifica )

Foto di Facebook

Stai commentando usando il tuo account Facebook. Chiudi sessione / Modifica )

Google+ photo

Stai commentando usando il tuo account Google+. Chiudi sessione / Modifica )

Connessione a %s...