bash, grep, sed, awk…: dinosauri o classici ?

Se siete degli utenti Windows questi comandi per voi risulteranno sconosciuti, ma sono il pane quotidiano degli amministratori UNIX/Linux.

Bash” è in realtà la “linea di comando”, attraverso la quale è possibile digitare manualmente dei comandi ( in nome tecnico la “shell” ), proprio come il “Dos Prompt” di Windows. Per analogia, uno script bash è analogo ad un “batch file” di Windows.

Grep” è invece un’utility che non esiste in Windows, ed è in sostanza un tool di ricerca all’interno di file di testo. Per esempio ‘grep chopin compositori.txt’ ritornerà le righe del file compositori.txt che contengono il nome ‘chopin’.

Sed” ( stream editor ) è un tool che prendendo in entrata un file effettua una serie di sostituzioni. Per esempio il comando sed s/chopin/mgutman/ compositori.txt sostituisce dentro il file compositori.txt il nome chopin con il nome mgutman.

Infine, “Awk” è lo strumento più complesso della famiglia, è anch’esso uno strumento di trasformazione come sed ma gestisce anche le colonne oltre alla righe ( per farla semplice )

Ho deciso di mettere alla prova questi strumenti sul mio Mac ( che è Unix ) creando uno script per la il download delle playlist youtube di liszt73 ( che ringrazio ancora )

Ho impiegato diverse ore per arrivare ad un qualcosa di funzionante, anche perchè alle mie prime armi. Ecco lo script:

#!/bin/bash 
 
function GetVideo {
videoUrl="http://it.youtube.com/watch?v=$1"
echo "url is:" $videoUrl
# scarica il sorgente della pagina, rimuovendo i caratteri newline \n
HTML=".source$1.html"
wget -q -o"$1".wget.log -O - $videoUrl | tr -d "\n" >$HTML
 
# estrai da un div il titolo del video
title=$(egrep -o '<div id="watch-vid-title" class="title">.<h1\ >[^<]*</h1>'<$HTML | sed 's/<div id="watch-vid-title" class="title">.<h1\ >\([^<]*\)<\/h1>/\1/' \
| tr ":" "-" | tr "/" "-")
echo "title is" $title
 
mv "$1".wget.log "$title".source.log
 
# estrai dal codice javascript l'hash ( variabile "t")
hash=$(egrep -o '\"t\": \"[-_a-zA-Z0-9]*\"' $HTML | egrep -o  '([-_a-zA-Z0-9]{2,})')
echo "hash is:" $hash
 
# dall'url estrai l'ID del video
video_id=$(echo $videoUrl | egrep -o 'v=[^\&]+' | egrep -o '[^=]{2,}')
echo "video_id is:" $video_id
 
# calcola l'URL per scaricare il video in formato MP4
mp4url="http://www.youtube.com/get_video?fmt=18&video_id=$video_id&t=$hash"
echo "mp4url is:" $mp4url
# ... e in formato Flash
flvurl="http://www.youtube.com/get_video?video_id=$video_id&t=$hash"
echo "flvurl is:" $flvurl
 
# scaricalo in background
wget -o"$title".log -O"$title".mp4 $mp4url || wget -o"$title".flv.log -O"$title".flv $flvurl &
 
# pulizia
rm $HTML
}
# invocare con yt_pl.sh playlistID( e.g. 6E6D77B78DCE77CA ) pagenr
 
out=".pl$1-$2.html"
plurl="http://it.youtube.com/view_play_list?p=$1&page=$2"
dList=".dl$1-$2"
info="$1page$2info.txt"
 
# salva il sorgente della pagina playlist 
wget -O$out $plurl 
 
# cerca nel sorgente i link ai video
cat $out | grep -o "<a href=\"/watch?v=[-_0-9a-zA-Z]*&feature=PlayList&p=[-_0-9a-zA-Z]*&index=[0-9]" | sort -u \
| egrep -o 'v=[-_0-9a-zA-Z]+&?' \
| sed -E 's/v=([-_0-9a-zA-Z]+)&?/\1/' >$dList
 
echo "Elenco ID" >> $info
cat $dList >> $info
echo "Sorgente HTML" >>$info
cat $out >>$info
 
 
# per ogni ID invoca la funzione GetVideoMP4
for i in $(cat $dList)
	do
	GetVideo $i
done
 
#pulizia
rm $out
rm $dList

Una volta salvato come ytpl.sh, per utilizzarlo dovete lanciare un comando del tipo:

./ytpl.sh  <playlistID> <numero totale di pagine>

Esempio

./ytpl.sh CA9F80F64D7C2400 2

In pratica lo script usa wget per scaricare i sorgenti delle pagine di youtube, ricavare alcuni parametri e generare gli URL di scaricamento, affidandoli ancora a wget. Alcune cose divertenti che si possono fare sono:

  • mettere in “piping” i comandi, ovvero l’output di un comando è reindirizzato all’altro tramite il carattere “|” . Questa possibilità da luogo ad un codice molto compatto.
  • mettere in una variabile i risultati di un comando tramite variabile=$(comando)
  • redirezionare l’output di un comando su un file o sullo schermo, tramite il carattere “>”
  • prevedere un comando di fallback nel caso che un comando fallisca. Nel mio caso, se fallisce il download dell’mp4 ( non sempre i video sono disponibili in mp4 ) , parte un download del flash. La sintassi è “comando1 || comando2″

Gli ostacoli più grandi che ho trovato sono stati:

  • Generare le corrette espressioni regolari ( per esempio lo standard grep non accetta “+” come quantificatore per 1 o più caratteri. E’ necessario usare egrep o l’opzione “-E” )
  • Capire come funzionano le sostituzioni della shell, quando usare le virgolette o meno, etc. etc.
  • Capire che senza togliere le newline ‘\n’ nei sorgenti HTML non avrei mai potuto usare grep o sed perchè sono utility che gestiscono la singola linea ( molti tag HTML sono su diverse linee ). Per non dovere imparare Awk :) , ho deciso di togliere le newline con il comando tr.

Chiaramente senza Google non avrei potuto fare niente, e in particolare questo tutorial è davvero eccezionale.

In conclusione direi che per questo tipo di problemi i tool si sono rivelati un’ottimo strumento, non credo che sarei mai riuscito a fare qualcosa del genere in C o VB, etc… D’altro canto è chiaro che non mi metterei a fare un gestionale con questi tool… :)

No Comment

No comments yet

Leave a reply