Shell: Parte 2¶
Redirezione¶
I comandi standard:
- prendono l’input da
stdin
, standard input; di defaultstdin
e’ l’input utente dato via terminale. - scrivono l’output in
stdout
, standard output; di defaultstdout
e’ il terminale. - scrivono eventuali messaggi di errore in
stderr
, standard error; di defaultstderr
e’ il terminale.
Possiamo modificare questi nomi simbolici usando gli operatori di redirezione:
cmd < file
costringecmd
ad usare i contenuti difile
comestdin
.cmd > file
costringecmd
a scrivere l’output nel filefile
. Sefile
non esiste viene creato, se esiste viene sovrascirtto.cmd >> file
costringecmd
a scrivere l’output nel filefile
. Sefile
non esiste viene crato, se esiste l’output viene aggiunto alla fine del file.
Warning
Non tutti i comandi permettono di redirigere lo stdin
. Tra
questi ci sono ls
e cat
.
Esempio. Lo stdout
di ls
puo’ comunque essere rediretto verso un
file arbitrario:
ls > lista_dei_file.txt
Esempio. Prendiamo il comando echo
: di default prende l’input
(stdin
) dal terminale (qui indicato come “keyboard”) e scrive (stdout
)
su terminale. Se lanciamo:
echo foo
quello che succede e’ che echo
replica (fa l’eco) di tutto quello che
scriviamo su terminale e lo stampa sul terminale. In immagini:

Redirigendo lo stdout
di echo
a file invece lo costringiamo a
redirigere il proprio output nel file:
echo foo > temp.txt
In immagini:

Esempio. Redirigere l’input di un comando funziona allo stesso modo.
Prendiamo il comando wc
. Di default prende l’input da schermo:
$ wc -w
foo
bar
baz
Control-d
qui Control-d
dice a wc
che l’input finisce li’. L’output sara’ 3
.
Pero’ possiamo costringere wc
a leggere l’input da file:
wc -w < temp.txt
In immagini:

Pipelines¶
Per eseguire piu’ comandi in sequenza, possiamo usare ;
:
cmd1 ; cmd2 ; ... ; cmdN
In questo modo la shell esegue cmd1
, poi cmd2
, ..., ed infine cmdN
.
Si possono combinare piu’ comandi in sequenza con l’operatore di
concatetenamento |
(pipe). La sintassi e’:
cmd1 | cmd2 | ... | cmdN
L’operatore |
collega lo stdout
di un comando allo stdin
del
comando che lo segue.

Note
Il simbolo |
rappresenta un tubo!
Esempio. Anticipando un po’ i tempi, se lancio:
ls | tac
ottengo che le righe stampata da ls
vengano prese da tac
, che le
stampa sottosopra.
Esempio. Per stampare su stdout
la lista dei file nella mia home
con ls
e poi contare le righe con wc
, scrivo:
ls -l ~ | wc -l
Posso passare argomenti ai vari comandi esattamente come se la pipeline non ci fosse.
Esempio. Per navigare comodamente l’output di una pipeline complessa:
cmd1 | ... | cmdN | less
Il comando less
permette di vedere l’output pagina per pagina. Potete
spostarvi nell’output come fareste nel manuale: vi spostate con le frecce,
potete cercare con /
, etc.
Modificare Files¶
I comandi di base sono:
comando | funzione | opzioni principali |
---|---|---|
echo |
stampa l’eco | -n |
cat |
stampa il contenuto di un file | -n |
tac |
stampa il contenuto sottosopra | |
head |
stampa l’inzio di un file | -n |
tail |
stampa la fine di un file | -n |
Esempio. Come gia’ visto sopra, il comando echo
puo’ essere usato per
creare file di testo, ad esempio:
echo 'I am the last line *ever*!' > output.txt
echo 'You are not, you /fool/!' >> output.txt
Qui le virgolette singole '
servono per evitare che la shell reagisca ad
eventuali caratteri speciali, nel nostro caso gli asterischi *
e gli
slash /
.
Esercizi¶
- Partendo da
~
, controllare il risultato dopo ogni passaggio: - Creare una directory
informatica
. E’ vuota? - Creare una directory
esercizi
. - Spostarsi in
informatica
. - Sempre da dentro
informatica
, rinominareesercizi
inesercizi-shell
. - Creare una copia di
esercizi-shell
ininformatica
. - Rimuovere la copia originale di
esercizi-shell
. - Creare in
informatica/esercizi-shell
un fileREADME
, il cui testo deve leggere: “esercitazioni di informatica
”. - Aggiungere a
README
una seconda riga: “Parte 1, introduzione alla shell
”. - Tornare alla propria home.
- Creare una directory
- Partendo da
- Partendo da
~
, controllare il risultato dopo ogni passaggio: Creare un file di testo
a
in una nuova directoryoriginal
. Il file deve contenere la stringa “*
”.Prima di ciascuno dei punti successivi, creare una copia di
original
chiamatatemp
.- Creare in
temp
due copie dia
, chiamateb
ec
. - Che differenza c’e’ tra
echo a
,ls a
ecat a
? - Che differenza c’e’ tra
mv a b
ecp a b; rm a
? - Che differenza c’e’ tra
cp a b; cp a c
emv a b; mv b c
? - Che differenza c’e’ tra
mv a z
emkdir z; mv a z
? - Che differenza c’e’ tra
echo a z
emkdir z; echo a z
? - Creare dieci file
a1
, ...,a10
, poi cancellarli con una sola invocazione dirm
.
- Creare in
- Partendo da
- Cosa fa il comando (alcuni dei seguenti comandi sono errati):
ls -e | head -n + 25
?cat | head | tail
?cat .
?echo cat
?cat a > b
?cat << a
?head > a | tail > b
?ls > a; rm < a
?echo KrustyIlKlown > a
?tac < FILE1 | tac > FILE2
- Che differenza c’e’ tra (alcuni dei seguenti comandi sono errati):
head < a > b
cat a | head > b
tac a | tac | head > b
tac < a | head | tac > b
- Che differenza c’e’ tra:
tac a | head -n 25 > b
cat a | tail -n 25 > b
- Che differenza c’e’ tra:
head a | tail
head a > temp; tail a
- Che differenza c’e’ tra:
cat file | head
cat | head file
- Come faccio a:
- stampare l’ennesima riga di un file?
- stampare le righe dalla
n
allan+m
di un file?
- Eseguire in ordine:
- Creare un file
data/b
che contenga le stesse righe didata/a
, ordinate dalla 26 alla 50, dalla 1 alla 25, e dalla 51 alla 100, in quest’ordine. - Creare un file
data/c
che contenga le stesse righe didata/a
, ordinate dalla 26 alla 50, dalla 25 alla 1, e dalla 51 alla 100, in quest’ordine.
- Creare un file
Soluzioni¶
- Soluzioni:
mkdir informatica
. Verifico che sia vuota conls informatica
.mkdir esercizi
.cd informatica
. Verifico conpwd
.mv ../esercizi ../esercizi-shell
. Verifico conls ..
.cp -r ../esercizi-shell .
. Verifico conls
.rm -r ../esercizi-shell
.echo 'esercitazioni di informatica' > esercizi-shell/README
. Verifico concat esercizi-shell/README
.echo 'Parte 1, introduzione alla shell' >> esercizi-shell/README
. Idem.cd
.
- Soluzioni:
mkdir original
, seguito daecho '*' > original/a
.Per comodita’, entro in
temp
concd temp
. Dopo ogni passaggio, faccio:cd .. rm -r temp cp -r original temp cd temp
Soluzioni:
cp a b; cp a c
. Verifico conls; cat b; cat c
.echo a
stampa la stringa “a
” a schermo;ls a
stampa il nome del filea
(che e’a
...);cat a
stampa il contenuto del filea
, cioe’ le due righe che abbiamo scritto prima.Nessuna.
mv a b
rinominaa
inb
.cp a b; rm aa
prima fa prima una copia dia
chiamatab
, poi rimuovea
.Nel primo caso mi ritrovo con tre copie di
a
, nel second con un solo file:c
.mv a z
rinominaa
inz
; quindiz
e’ un file.mkdir z; mv a z
prima crea una directoryz
, poi ci mette dentroa
.echo a z
stampa a schermo la stringaa z
.mkdir z; echo a z
fa la stessa cosa, ma crea anche una directory di nomez
.Cosi’:
echo qualcosa > a1 ... echo qualcosa > a10 rm a*
- Soluzioni:
- Da’ errore.
-e
non e’ un’opzione valida perls
. - Si pianta.
cat
si aspetta un file di input: noi non glielo diamo, e lui resta in attesa. Dato checat
e’ fermo, il resto della pipeline resta in attesa. Siamo costretti ad uccidere la pipeline conControl-c
. - Da’ errore.
.
e’ una directory,cat
si aspetta un file. - Stampa la stringa “
cat
” a schermo. (Non esegue il comandocat
...) - Stampa il contenuto del file
a
(se esiste), ma visto che lostdout
e’ rediretto, mette l’output dicat
nel fileb
. E’ equivalente acp a b
. - Da’ errore:
<<
non e’ un operatore di redirezione valido. - Non ha senso: stiamo cercando di redirigere lo
stdout
dihead
sia verso il filea
che, con la pipe|
, verso lostdin
ditail
. ls
mette ina
la lista dei file nella directory corrente; fin qui tutto ok. Mairm
non supporta la redirezione, si aspetta invece il nome di un file! Quindi finisce per dare errore.- Scrive il testo “
KrustyIlKlown
” nel filea
. - Il primo
tac
leggeFILE1
lo stampa a schermo rovesciato; pero’ la pipe ne redirige lostdout
al secondotac
: l’effetto complessivo e’ cheFILE1
viene stampato a schermo nel verso giusto. Infine, l’ultimo>
mette il contenuto diFILE1
inFILE2
. Il tutto e’ equivalente acp FILE1 FILE2
.
- Da’ errore.
- Soluzioni:
- Stampa le prime dieci righe di
a
inb
. - Idem.
- Idem.
- Stampa le ultime dieci righe di
a
inb
.
- Stampa le prime dieci righe di
- Soluzioni:
- Stampa
a
sottosopra, prende le prime venticinque righe, le mette inb
. Quindib
contiene le ultime venticinque righe dia
sottosopra. - Stampa
a
, prende le ultime venticinque righe, le mette inb
. Quindib
contiene ultime venticinque righe dia
ma non sottosopra.
- Stampa
- Soluzioni:
- Stampa le prime dieci righe di
a
. - Mette le prime dieci righe di
a
nel filetemp
, poi stampa le ultime dieci righe dia
.
- Stampa le prime dieci righe di
- Soluzioni:
- Stampa
file
e ne tiene solo le prime dieci righe. - Si pianta. Come sopra,
cat
si aspetta un file in input; non non glielo diamo e lui resta in attesa.
- Stampa
- Soluzioni:
- Stampo le prime n del file, di queste tengo solo l’ultima:
head -n n file | tail -n 1
. - Assumiamo che tot=n+m. Stampo le ultime tot righe del file, di queste tengo solo le ultime m:
head -n tot file | tail -n m
.
- Stampo le prime n del file, di queste tengo solo l’ultima:
- Soluzioni:
Eseguo:
head -n 50 data/a | tail -n 25 > data/b head -n 25 data/a >> data/b tail -n 50 data/a >> data/b
Come sopra, ma il secondo comando diventa:
head -n 25 data/a | tac >> data/b