[successivo] [precedente] [inizio] [fine] [indice generale] [hall of fame] [indice analitico] [parte]


Capitolo 12.   Programmazione

12.1   Script per la shell

12.1.1)   Perché il comando cd non funziona negli script?

Se si esegue il seguente script:

#!/bin/sh
cd /home/aur
ls -la --color

il risultato sarà la visualizzazione del contenuto della directory /home/aur/. Quello che accade però, è che la posizione della shell all'interno del file system non sarà /home/aur/ ma risulterà essere quella da cui lo script è stato invocato. Questo accade perché lo script viene eseguito da una shell secondaria (/bin/sh), che si chiude quando lo script stesso termina la sua esecuzione. Pertanto la shell perde tutte le impostazioni e le variabili (compresa PWD, cioè il percorso della directory corrente). Per ovviare a tale comportamento si potranno utilizzare due metodiche. La prima prevede l'utilizzo di source:

source nomescript[Invio]

La seconda consiste nell'apporre al comando il punto (.):

. nomescript[Invio]

in questo caso infatti sarà la shell corrente ad eseguire i comandi e non un processo figlio.

12.1.2)   Come si può eseguire uno script di shell attraverso il protocollo HTTP?

Si può ottenere il risultato richiesto utilizzando i file .cgi con permessi 755:

chmod 755 file.cgi[Invio]

e richiamando mediante collegamento simbolico o fornendo l'indirizzo esatto. Il contenuto di un file .cgi può essere qualunque linguaggio interpretato o compilato che sia in grado di leggere lo standard input, scrivere su standard output e leggere il contenuto delle variabili d'ambiente.

12.1.3)   Esiste un comando o un sistema per contare le righe presenti in un file di testo?

cat nomefile | wc -l[Invio](1)

12.1.4)   Esiste un comando o un sistema per contare i caratteri presenti in un file di testo?

cat nomefile | wc -c[Invio](2)

12.1.5)   Come si fa a sapere lo stato di uscita di un comando?

Si può ottenere questa informazione utilizzando il parametro speciale ?. Prendendo come esempio la visualizzazione del contenuto di una directory e impartendo il seguente comando:

ls ; echo -e "\nEXIT_CODE: $?\n"[Invio]

verrà restituito 0 se l'esito è stato positivo. Il comando appena esposto restituirà il seguente output:

EXIT_CODE: 0

Qualora invece il comando non abbia avuto successo, come ad esempio potrebbe accadere nella visualizzazione di una directory che non esiste:

ls directory_che_non_esiste; echo -e "\nEXIT_CODE: $?\n"[Invio]

Il comando avrà un esito negativo e restituirà quanto segue:

EXIT_CODE: 1

12.1.6)   Che differenza c'è tra $@ e $# all'interno degli script shell?

Per capire la differenza tra i due parametri posizionali $@ e $#, sarà sufficiente creare il seguente script fornendogli il nome di prova

#!/bin/bash

echo $@;
echo $#;

Ora, dopo avergli fornito i permessi di esecuzione:

chmod u+x prova[Invio]

lo si potrà invocare. A scopo didattico verranno forniti tre argomenti:

./prova ciao bla "un esempio"[Invio]

L'output del comando è abbastanza chiaro: $@ restituirà tutti i parametri passati tramite la linea di comando, mentre $# indicherà la posizione dell'ultimo di essi, nel nostro caso 3.

Se si aggiunge allo script anche la riga:

echo $3

verrà restituito il terzo argomento (un esempio).

12.1.7)   Come si eliminano le prime n righe o le ultime n righe per numerosi file di testo?

A tale scopo utilizziamo vim, caricando i file da modificare tutti in una volta:

vim file1 file2 file3 file4 file5[Invio](3)

A questo punto impartiamo il comando dopo essere entrati nella modalità che lo consente mediante la pressione del tasto [ESC]:

[...]
~
~
~
~
~
:nmap z gg:d10<CR>G20kd20<CR>:w<CR>:n<CR>

Questo comando permette di rimappare il tasto [z] in vim. Mediante la sola pressione di tale tasto infatti, sarà possibile cancellare le prime 10 righe e le ultime 20 del file di testo correntemente visualizzato, esso verrà inoltre memorizzato e verrà aperto il file successivo.(4)

Quando vim avrà modificato l'ultimo file aperto, avvertirà che non ce ne sono altri cui applicare le operazioni. A questo punto si dovrà salvare ed uscire con :wq

[...]
~
~
~
~
~
:wq

12.1.8)   Come si cancellano tutte le righe di un file che cominciano con una determinata stringa?

Ammettiamo che la stringa sia «pD:». Facendo riferimento alla LDR 12.1.7 si dovrà modificare la mappatura del tasto [z] questo modo:

:nmap z /pD\:<CR>dd

Il «\» davanti a «:» protegge quest'ultimo carattere dall'interpretazione di vim.

12.1.9)   Come si aggiungono i numeri di riga ad un file di testo?

Si può numerare un file di testo con Perl. Si crei ad esempio il file tizio.pl contenente quanto segue:

#!/usr/bin/perl 

$nr=0;
while (<STDIN>) {
                              print sprintf("%04d: %s",$nr,$_);
                              $nr++;
                             }
exit;

Si conferiscano i relativi permessi di esecuzione mediante:

chmod u+x tizio.pl[Invio]

Il comando:

cat sempronio.txt | ./tizio.pl > filenumerato[Invio](5)

creerà il file filenumerato. Per ottenere lo stesso scopo si potrà utilizzare awk:

cat sempronio.txt | awk '{print FNR,$0}'[Invio]

reindirizzando opportunamente l'output su un file destinazione.

12.1.10)   Come si sceglie un file a caso in una directory?

Se si desidera scegliere un file a caso nella directory corrente si potrà utilizzare il seguente comando che si avvale di sed e random:

ls -1 | sed -e $(random -e `ls -1 | wc -l` ; echo $(( RAND=$?+1 )))p --quiet[Invio]

Si può sopperire alla mancanza di random con l'equivalente in Perl:

perl -e '@files=`ls -1`;print "@files[int(rand($#files))]\n";'[Invio]

12.1.11)   Come si visualizzano i file modificati negli ultimi n minuti?

Se si intende farlo nella directory corrente e nelle sue discendenti il comando sarà:

find . -mmin -30 -exec grep -l aabbcc "{}" \;[Invio]

se invece si intende farlo in tutto il file system, si impartirà il seguente comando:

find / -mmin -30 -exec grep -l aabbcc "{}" \;[Invio]

12.1.12)   Come si ricercano file doppi?

Per cercare in una directory e nelle relative discendenti, se ci sono o meno dei file con nomi uguali e per reindirizzare il risultato di questa ricerca su un file di testo si potrà utilizzare il seguente script

#!/bin/sh
# $1= directory dove cercare i file.

for $i in `find $1 -name *`; do
        $n= basename $i
        if [ `find $1 -name $n |wc -l` -gt 1]; then
                find $1 -name $n
        fi
done

Ecco un metodo alternativo:

for F in `ls -1 -R percorso_dir1`; do find percorso_dir2 -name $F; done > lista_files_doppi[Invio](6)

12.1.13)   Come si convertono in minuscolo tutti i nomi dei file di una directory?

Ci si può avvalere di diverse metodiche (comandi e script) per rinominare in minuscolo tutti i file di una directory:

  1. perl -e '@files = `ls -1`; (segue)
       chop @files; foreach $f(@files){!-e lc($f) && rename ($f, lc($f))}'
    [Invio]

  2. for FILE in `/bin/ls`; do FILELOWER=`echo $FILE | (segue)
       tr A-Z a-z`; mv -i $FILE $FILELOWER; done
    [Invio]

  3. for i in *
    do
      echo $i
      j = `echo $i | dd conv=lcase 2>&-`
      mv $i $j
    done
  4. for i in *
    do
       mv -i `echo $i | awk '{print  tolower($1)}'  -`
    done

12.1.14)   Come si convertono in minuscolo i nomi dei file nei collegamenti ipertestuali di una pagina HTML?

Se si dispone di una pagina HTML con dei collegamenti a file che hanno lettere maiuscole e minuscole, ad esempio:

<A HREF="/dir-a/dir-b/pAGInA.html">

e si volesse convertire i nomi dei file in minuscolo (pAGInA.html > pagina.html) si potrà utilizzare il seguente comando:

cat pagina.html | perl -e 'while($l=<STDIN>){$l=~s/a href=\"(.*)\"\s*/a \href=\"\L$1\" /ig;print $l;}' > convertita.html [Invio](7)

12.1.15)   Come si converte un elenco di nomi di file .html in collegamenti ipertestuali?

Se si dispone di un file di testo composto da tante righe ognuna delle quali è il nome di un file HTML:

 file1.html
 file2.html
 file3.html
 file4.html
 [...]
 file34575.html

sarà possibile trasformare queste righe in altrettanti collegamenti ipertestuali. Per farlo sarà sufficiente utilizzare il seguente comando (shell Bash):

for i in `cat elenco.txt`; do echo "<a href="$i">$i</a>"; done > filedestinazione.html [Invio](8)

Si pensi inoltre ad una directory contente molte immagini (.png, .jpg, ecc.). Mediante tale comando si potrà creare un file .html con un elenco facilmente accessibile da qualsiasi navigatore.

12.1.16)   Come si ordinano le righe di un file di testo al contrario?

Se si desidera che un file del tipo:

aaa
bbb
ccc
ddd
eee
fff

venga convertito in:

fff
eee
ddd
ccc
bbb
aaa

si potrà utilizzare il seguente comando:

cat -n nome_file | sort -r | (segue)
   awk '{$1="";print}' | sed -e s/\ // > nuovo_file
[Invio](9)

oppure:

cat nome_file | perl -e '@a=< STDIN >; (segue)
   while(@a){print pop(@a)};' > nuovo_file
[Invio]

Non basta il semplice:

cat nome_file | sort -r > nome_file.rev[Invio]

che funzionerebbe se il primo campo di ogni riga fosse la data in formato aa/mm/gg. Se invece il formato è gg/mm/aa le righe verrebbero ordinate in base al giorno e non in base all'anno.

12.1.17)   Come si utilizza Sed per sostituire il testo?

Ecco un esempio simpatico per capire come funziona Sed, per la sostituzione di testo:

echo 'Il miglior sistema operativo: Windows' | sed /Windows/s//Linux/g[Invio]

12.1.18)   Quante volte appare una parola in un file?

Per sapere quante volte compare una parola in un file si darà il seguente comando

grep parola file|wc -w[Invio]

12.1.19)   A cosa serve l'opzione -f (if) negli script della shell?

Il seguente script:

#!/bin/bash

if [ -f "$1" ]; then 
        echo "file regolare";
fi

analizza l'argomento fornitogli. Se quest'ultimo rappresenta un file regolare, lo script lo segnala. Per file regolare si intende un qualsiasi file normale, che non sia quindi un dispositivo, una directory, ecc.

12.1.20)   Come si può utilizzare date negli script della shell?

In alcuni script per la shell a volte è necessario utilizzare la data. Utilizzando però esclusivamente il comando date vengono restituite informazioni a volte inutili. Per eliminarle si utilizzano del opzioni da aggiungere al comando date stesso.

Ad esempio il comando:

echo `date +%x`[Invio]

restituisce il formato: gg/mm/aa. Utilizzare invece:

echo `date +%x` | sed "/\//s///g" [Invio](10)

per ottenere il formato: ggmmaa (senza /). Lo stesso risultato lo si ottiene anche con:

echo `date +%x | sed 's/\///g'`[Invio]

Con i parametri %d %m %y %Y si possono ottenere tutte le combinazioni per manipolare il formato della data. Ad esempio:

date +%Y%m%d[Invio]

restituirà:

20010304

Il parametro %Y restituisce l'anno a quattro cifre mentre %y quello a due.

12.1.21)   Come si fa a cercare tutti i file di un certo tipo (es. *.png) e a copiarli in una directory?

Se la directory di destinazione è /root/pngfile, il comando sarà:

find / -name "*.png" -exec cp -p {} /root/pngfile \; [Invio]

12.1.22)   Come si cambiano le estensioni dei file?

Ecco uno script che permette di cambiare le estensioni di gruppi di file dello stesso tipo presenti nella directory corrente:

#!/usr/bin/perl

$old_ext = @ARGV[0] || usage();
$new_ext = @ARGV[1] || usage();

print "$old_ext --> $new_ext\n\n";

@files = `ls -1`;
chop @files;

foreach $f(@files) {
        $f =~ /(^.*)\.$old_ext/ && rename ($f, "$1.$new_ext");
}

sub usage {
        print <<"END";

        Usage: ./script.pl old_ext new_ext

        Example: ./script.pl tar.gz zip

END
        exit(1);
}

Occorre fornire i permessi di esecuzione e occorre invocarlo nella directory in cui si devono rinominare i file ponendo come primo argomento l'estensione da cambiare e come secondo l'estensione che si desidera. Esempio:

converti jpeg jpg[Invio](11)

Ecco un altro metodo per ottenere lo stesso scopo:

for i in *.vecchiaest; do echo $i | mv $i `awk -F. '{print $1 ".nuovaest"}'`; done [Invio]

o più semplicemente:

for i in *.vecchiaest; do mv $i ${i%.vecchiaest}.nuovaest; done [Invio]

Se i file sono tanti e si eccede la lunghezza massima di una riga di comando, si può impartire:

find . -name "abc*.txt" | while read i; do mv $i ${i%.txt}; done[Invio](12)

12.1.23)   Come si può modificare l'output di pppstats?

Il comando

pppstats -r -v ppp0[Invio]

restituisce qualcosa del genere::

      IN   PACK VJCOMP VJTOSS NON-VJ  RATIO  UBYTE
   48089    366     16      0     99   1.00      0  
      OUT   PACK VJCOMP VJSRCH VJMISS  RATIO  UBYTE
   308840    385     54    212      8   1.00      0

Se si dovesse avere la necessità di eliminare la prima riga e avere la seconda tale e quale, ma al posto degli spazi dei caratteri di tabulazione, si potrà procedere come segue (13):

pppstats -r -v ppp0 | (segue)
   grep -v VJCOMP | perl -e '$i=<STDIN>; (segue)
  $i=~s/\s+/\t/g;print $i;' | cut -f 2-
[Invio]

perl -e '@a=split(/\s+/, `pppstats -r -v ppp0| (segue)
  grep -v VJCOMP`);shift(a); (segue)
  foreach $b(@a) {print "$b\t"};'
[Invio]

pppstats -r -v ppp0 | grep -v OUT | (segue)
   sed -e 's/\ \+/ /g' | cut -f 2-
[Invio](14)

12.1.24)   Come si trovano tutti gli indirizzi di posta elettronica in un file HTML?

Per ricavare da una pagina HTML tutti gli indirizzi di posta elettronica si potrà utilizzare l'interprete Perl:

cat file.html | perl -e 'while ($l=<STDIN>) (segue)
   {$l=~/mailto:\s*([\w-_\.]+\@[\w-_\.]+\.[\w-_\.]+)/ && print "$1\n";}'
[Invio]

Se gli indirizzi da estrapolare non compaiono sotto forma di tag (marcatore) HTML, si dovrà togliere la stringa relativa al mailto e lo spazio nell'espressione regolare.

12.1.25)   Come si aggiunge una stringa alla fine di ogni riga di un file testo?

Per aggiungere una stessa stringa alla fine di ogni riga di testo si darà il seguente comando:

cat file -name | sed "s/$/testo/"[Invio]

dove testo è la stringa da aggiungere.

12.1.26)   Esempio di uno script per decomprimere file in directory sequenziali.

Se si dispone di n file compressi con gzip, e si desidera decomprimerne il contenuto in n directory differenti, si potrà utilizzare il seguente script:

#!/bin/sh
cd /gzipdir/
for f in *
do
    mkdir /destinazione/$f
    unzip $f -d /destinazione/$f
done

Lo script assume che tutti i file compressi risiedano in /gzipdir/ e che la directory /destinazione/ esista già.

12.2   Linguaggio C

12.2.1)   Cosa sono i file .h, .o e .c in un programma C?

Supponendo di lavorare sul file miofile, il codice sorgente vero e proprio viene scritto in miofile.c. miofile.h, detto file di intestazione contiene le dichiarazioni delle variabili e delle funzioni implementate nel file miofile.c.

Infine il codice oggetto risultante dalla compilazione risiederà in miofile.o.

12.2.2)   Come si avvia il compilatore C++?

Tale compilatore si può avviare con:

g++ -o nomefile nomefile.cpp [Invio]

L'opzione -o serve a dare un nome all'eseguibile diverso dal nome predefinito, che è a.out.

12.2.3)   Bus Error

Solitamente l'errore Bus Error si verifica per un superamento dei limiti di memoria, un indice di un array che supera il limite, un fine-stringa mancante ecc.

Per risalire all'origine del problema, occorrerà compilare il sorgente con l'opzione -g ed eseguirlo. Quando si interrompe l'esecuzione del programma stesso, si potranno analizzare le cause con:

dbx nomeprogr core[Invio](15)

e tramite l'istruzione where si potrà visualizzare il punto in cui si è verificato l'errore.

12.2.4)   Esiste in GNU/Linux il file conio.h?

Su <sunsite.unc.edu> è presente un file che si chiama linux-conio-x.yy.tgz che sostituisce il conio.h.

12.3   Pascal

12.3.1)   Si può convertire un programma scritto in Pascal in C?

Esiste p2c Pascal-to-C. Dato un sorgente Pascal, esso genera un altro sorgente C che è possibile compilare tranquillamente con gcc.

Il nome di Pascal-to-C è indicato dal suo autore come P2c. Tuttavia, P2C è anche il nome di un altro compilatore analogo, realizzato per sistemi speciali: <http://www.geocities.com/SiliconValley/Network/3656/p2c/linux.html>. In questo secondo caso, oltre alla particolarità del compilatore stesso, c'è da considerare il fatto che non si tratta di software libero.

12.4   Cobol

12.4.1)   Esistono dei compilatori Cobol per GNU/Linux?

Eccone alcuni:

  1. Cobol2c (16); (in sviluppo: <http://www.gnu.org/software/cobol/cobol.htm>)

  2. Tiny Cobol (17);

  3. RPCobol (18);

12.5   Perl

12.5.1)   Come si installano i moduli Perl?

Il modo migliore per installare i moduli in Perl è tramite il comando:

perl -MCPAN -eshell[Invio]

Al prompt occorre digitare:

install Tk[Invio]

(Tk in questo caso è un esempio di modulo da installare) Sarà necessaria una breve fase di configurazione guidata se si installano i moduli in questo modo per la prima volta, ma tutta la fase di scarico del modulo, test e installazione è automatica. Essa comprende anche eventuali installazioni di moduli necessari a quello in oggetto. In alternativa, per installare un modulo Perl a mano, dopo averlo scompattato ed essere entrati nella directory dove è stato decompresso, si può inizializzare la procedura di installazione con:

perl Makefile.PL[Invio]

Il modulo viene creato mediante il comando:

make[Invio]

provato mediante:

make test[Invio]

ed installato con:

make install[Invio]

durante tutte queste fasi si possono presentare inconvenienti, ad esempio altri moduli da installare che sono necessari a quello in oggetto, oppure test falliti per qualche ragione.

LDR --- Copyright © 1999-2001 Gaetano Paolone --  bigpaul @ linuxfaq.it

1) dove nomefile è il nome del file di cui vogliamo contare le righe

2) dove nomefile è il nome del file di cui vogliamo contare i caratteri

3) è possibile utilizzare anche i caratteri di sostituzione (* e ?)

4) Sarà sufficiente sostituire 10 e 20 con i valori desiderati

5) dove sempronio.txt è il file da numerare

6) dove per percorso_dir1 si intende il percorso completo della prima directory da confrontare, e per percorso_dir2 il percorso della seconda. lista_files_doppi sarà il file di testo contenente l'elenco dei file doppi

7) dove pagina.html è la pagina da convertire e convertita.html è la pagina risultato della conversione.

8) dove elenco.txt è l'elenco dei file .html e filedestinazione.html è la pagina ipertestuale risultato della conversione.

9) dove nome_file è il file da convertire e nuovo_file il file risultato della conversione.

10) le virgolette sono necessarie a causa della \

11) ammesso che lo script sia stato chiamato converti.

12) prestare attenzione: find è ricorsivo.

13) Questa metodica è utile se si desidera analizzare i dati sulle connessioni con un foglio di calcolo (Gnumeric, ecc.)

14) N.B.: nella parte con il Sed il tab è scritto con [Ctrl+v] e [tab]

15) nomeprogr è il nome del programma

16) Cobol2c   GPL

17) Tiny Cobol   GPL

18) RPCobol   GPL


Dovrebbe essere possibile fare riferimento a questa pagina anche con il nome programmazione.html

[successivo] [precedente] [inizio] [fine] [indice generale] [hall of fame] [indice analitico]