====== Esercitazione 3 ====== ===== Esercizio 1: ridefiniamo 'cd' ===== Ridefinire il builtin //cd// usando una **funzione cd** in modo che con 0 o 1 parametri si comporti come il builtin //cd// mentre con 2 parametri, ad esempio: cd old new sostituisca tutte le occorrenze di //old// nella working directory corrente con //new// e poi cerchi di spostarsi nel path cosi' generato (se esiste ed e' una directory). Gestire anche le situazioni di errore. Utilizzare il costrutto //case// per discriminare fra il numero dei parametri forniti alla funzione (vedi esempio nella lezione 3 su bash). ===== Esercizio 2: icd, interactive cd ===== Definire la funzione **icd** (interactive cd) in modo che elenchi le directory presenti nella directory corrente e chieda inrterattivamente all'utente in qualse vuole spostarsi. Ad esempio: bash:~$ icd 1) pippo/ 2) pluto/ 3) paperone/ Quale scegli? 3 bash:~/paperone$ Si usi il costrutto //select// per interagire con l'utente settando opportunamente la variabile di prompt. Avanzato: estendere icd in modo che accetti come parametro il path della directory in cui effettuare la scelta. ===== Esercizio 3: printpath ===== Definire la funzione printpath che stampa una per linea tutte le directory presenti nella variabile di ambiente //PATH// (separatore ':') una per linea. Ad esempio bash:~$ printpath /home/susanna/bin /usr/local/bin /usr/bin /usr/X11R6/bin /bin /usr/games /opt/gnome/bin /opt/kde3/bin /home/susanna/local/bin . bash:~$ Attenzione: il separatore ':' deve essere rimosso. ===== Esercizio 4: printusr ===== Definire una funzione **printusr** che stampi i nomi dei primi 10 utenti della macchina ordinati lessicograficamente (vedi file /etc/passwd) con la loro home. Ad esempio bash:~$ printusr at:/var/spool/atjobs bin:/bin daemon:/sbin francy:/home/francy ftp:/srv/ftp games:/var/games gdm:/var/lib/gdm irc:/usr/lib/ircd ldap:/var/lib/ldap lp:/var/spool/lpd bash:~$ Chi riesce a farlo in meno linee di codice? ===== Esercizio 5: opzioni : mykeyselect ===== Scrivere uno script mykeyselect [-a][-b barg][-c carg] file //file// contiene su ogni riga delle coppie chiave valore dove ''valore'' e' un valore numerico. Lo script stampa la lista ordinata delle N chiavi di minor valore nel file. ''N'' e' pari a 4 se l'opzione ''-b'' non e' specificata altrimenti ''N=barg''. Se ''-a'' e' specificata si stampano le chiavi di maggior valore e non quelle di monor valore. Se e' specificata l'opzione ''-c'', vengono ignorate tutte le righe che contengono ''carg''.\\ Le gestione delle opzioni deve avere le seguenti proprieta': * le opzioni possono essere fornite in un qualsiasi ordine ma sempre prima del nome del file (es: mykeyselect -b 20 -a filename mykeyselect -c -a -b 30 filename * e' possibile specificare opzioni multiple con un singolo 'dash' (in questo caso solo l'ultima puo' avere un argomento opzionale). es: mykeyselect -ac gigi * e' possibile omettere lo spazio fra opzione ed argomento es: mykeyselect -b20 -a filename mykeyselect -cgigi -a -b 30 filename mykeyselect -acgigi filename //Suggerimenti: Utilizzare sort per effettare il sorting, in particolare verificare sul man le opzioni -n e -k. Utilizzare i builtin **shift** e **getopts** per effettuare il persing della linea di comando. Essendo builtin le informazioni in linea si possono accedere da **man bash**. Una spiegazione piu' accurata del funzionamento di getopts (con esempi) e' disponibile in linea [[http://www.mkssoftware.com/docs/man1/getopts.1.asp|qua]] oppure [[http://uw713doc.sco.com/en/man/html.1/getopts.1.html|qua]].// ===== Esercizio 6: interi : totdu ===== Sviluppare uno script: totdu [ ... ] che per ogni argomento che sia una directory stampa lo spazio utilizzato dalla directory e da tutte le sue sottodirectory, in byte e Kbyte (se >1KB) oppure in byte e Mbyte (se >1MB). Se non viene specificata alcuna directory si forniscono informazioni sulla directory corrente. Ad esempio: bash:~$ totdu ciccio pippo ciccio: Totale 18098176 byte 17 MB pippo: Totale 14336 byte 14 KB //Suggerimenti: Utilizzare **du** per i byte occupati. Il comando **cut** puo' essere utile per selzionare un'opportuna colonna dell'output. Notare che nelle espressioni intere si puo' specificare un numero in base diversa da 10 con la notazione **base#numero** es: 16#400 per 1024.// ===== Esercizio 7: self exec shell ===== Provare ad eseguire: #!/bin/bash # self-exec.sh echo "This line appears ONCE in the script, yet it keeps echoing." echo "The PID of this instance of the script is still $$." # The same shell always running echo "==================== Hit Ctl-C to exit ====================" sleep 1 exec $0 echo "This line will never echo!" # Why not? exit 0 che succede? perche? ===== Esercizio 8: makecmd: a simple make ===== Implementare una funzione ''makecmd'' in grado di interpretare un singolo costrutto del tipo target: source1 .. sourceN cmd1 .... cmdK fornito sullo standard input secondo la usuale semantica 'make' (la lista di comandi viene eseguita se il target non esiste oppure se e' stato modificato l'ultima volta in tempi precedenti rispetto ad almeno uno dei source nella dependency list, ogni comando viene prima stampato su stdout e poi eseguito). Se un source nella dependency list non esiste si considera la dipendenza verificata (!= semantica make). Ad esempio: bash:~$ more makefile a : b c d echo "Sto eseguendo!" bash:~$ makecmd < makefile echo "Sto eseguendo!" Sto eseguendo! Utilizzare il builtin ''read'' per leggere dallo standard input, ed ''eval'' per invocare la esecuzione di un comando della lista.