Programmino shell, cosa non va?

fk16
Ragazzi secondo voi cosa c'è di errato nella sintassi di awk?
#!/bin/sh

###################################################################################
#Si implementi uno script di shell che trova, a partire da una cartella radice,   #
#tutti file di tipo .txt, .rtf e .odt che al suo interno hanno le parole con le   #
#seguenti caratteristiche:                                                        #
#-hanno il prefisso 'un';                                                         #
#-hanno almeno sei caratteri;                                                     #
#-gli ultimi due caratteri sono delle vocali.                                     #
###################################################################################

clear

if [ ! -d "$1" ]
  then
    echo "Errore nell'input"
    echo "Cartella inesistente"
    exit 1
else
    root_dir="$1"
fi

#Cerco tutti i file che hanno la data estensione!
filetxt=`find $root_dir -name *.txt`
filertf=`find $root_dir -name *.rtf`
fileodt=`find $root_dir -name *.odt`

#Concateno questi file in un unico file
files="$filetxt $filertf $fileodt"

for i in $files
   do
   cat $i | awk " ~ /^[un]*{6}[a|e|i|o|u]$/"
   done

Risposte
Studente Anonimo
Studente Anonimo
Proverei a usare i singoli apici e un
$0
prima dell'operatore
~
, così:

cat $i | awk '$0 ~ /^[un]*{6}[a|e|i|o|u]$/'

L'espressione regolare però non mi sembra corretta, inoltre devi trovare quali file contengono quelle parole o visualizzare le parole trovate?

fk16
"anonymous_be1147":
Proverei a usare i singoli apici e un
\( 0
prima dell'operatore
~
, così:
 cat \)i | awk '\( 0 ~ /^[un]*{6}[a|e|i|o|u] \)/'

L'espressione regolare però non mi sembra corretta, inoltre devi trovare quali file contengono quelle parole o visualizzare le parole trovate?

Ma il fatto di mettere il pattern /^[un]*{6}[a|e|i|o|u]/
mi dice di prendere le parole che iniziano con un (^[un]) che sono composte da 6 o più lettere (*{6}) e che terminano con una vocale ([a|e|i|o|u]$). E' sbagliato secondo te?

fk16
comunque deve trovare quei file che contengono quelle parole, e non stampare le parole.

Studente Anonimo
Studente Anonimo
"fk16":
Ma il fatto di mettere il pattern /^[un]*{6}[a|e|i|o|u]/
mi dice di prendere le parole che iniziano con un (^[un]) che sono composte da 6 o più lettere (*{6}) e che terminano con una vocale ([a|e|i|o|u]$). E' sbagliato secondo te?


Dipende da cosa e dove vuoi cercare. Quell'espressione io la leggo così:
trova all'inizio della riga una lettera u oppure una lettera n, questa lettera può essere ripetuta zero o più volte, quello che hai trovato prima deve essere ripetuto 6 volte, quindi deve esserci una vocale oppure un carattere di pipe, alla fine della riga. E questo probabilmente non è quello che vuoi.

Io procederei così per "costruire" l'espressione regolare. Le parole da cercare devono avere almeno 6 caratteri.

i primi due caratteri devono essere una u seguita da una n :arrow:
/un/
, gli ultimi due devono essere vocali :arrow:
/un[aeiou]{2}/
. Siccome la parola deve essere lunga almeno 6 caratteri, in mezzo ci devono essere almeno due caratteri qualsiasi (alfanumerici) :arrow:
/un[[:alnum]]{2,}[aeiou]{2}/
.

Ora siccome si stanno cercando delle parole intere, bisogna considerare i confini delle parole (cio che segna l'inizio e la fine), altrimenti ci potrebbe essere corrispondenza su parti di parole più lunghe. Quindi l'espressione regolare finale diventerebbe
/\/
.

Ovviamente ci sono altri modi per scrivere quest'espressione, dipende in genere da quale implementazione di awk stai usando, e questo è solo uno spunto. Volendo ci sarebbero altre considerazioni da fare sullo script.

P.S. Se non devi per forza usare
awk
e
find
, puoi comodamente ripiegare su
egrep
che tramite le sue opzioni ti stampa il nome dei file dove c'è corrispondenza su tutta un directory specificata.

egrep -l '\<un[[:alnum:]]{2,}[aeiou]{2}\>' -r DIRECTORY_DA_ANALIZZARE

fk16
Innanzi tutto ti ringrazio del tuo aiuto, sei stato gentilissimo e mi è stato tutto molto chiaro!
Comunque se non ti è disturbo ti posso chiarimento su un'ultima cosa?
In pratica ho il seguente esercizo svolto nel seguente modo da me:
#!/bin/sh

############################################################
#Scrivere uno script di shell, rmhid, che data una cartella#
#radice di partenza elimini tutti i file e le cartelle     #
#nascoste al suo interno (le operazioni devono essere      #
#eseguite ricorsivamente all'interno delle sottocartelle   #
#della cartella radice).                                   #
#Ad esempio, rmhid /tmp elimina ricorsivamente tutti i file#
#e le cartelle nascoste a partire dalla cartella /tmp.     #
############################################################

#Controllo i paramentri
if [ $# -ne 1 ]
  then
    echo "Errore nell'input"
    echo "Usare: $0 [directory]"
  exit 1
fi

if [ ! -d $1 ]
  then
    echo "La directory non esiste"
    exit 1
else
    dir=$1
fi

rmhid()
{
curr_dir="$1"

for i in `ls -a $curr_dir/\.`
   do
#per sicurezza simulo la rimozione con echo
    echo "Rimuovo il file $i"
   done

for i in `ls $curr_dir/*`
   do
    if [ -d "$i" ]
      then
        echo "$i è una sotto directory"
        rmhid $i
    fi
   done
}

rmhid "$dir"

Ti spiego quale è il problema. In pratica Nel seguente ciclo for:
for i in `ls -a $curr_dir/\.`
   do
#per sicurezza simulo la rimozione con echo
    echo "Rimuovo il file $i"
   done

la i dovrebbe assumere i nomi dei file che cominciano con '.' , invece mi vengono presi tutti i file della certella passata come argomento. Mi potresti spiegare il motivo?

Studente Anonimo
Studente Anonimo
Be', non funziona perché il punto indica come sai anche la directory corrente. Secondo me dovresti innanzitutto rimuovere le directory '.' e '..' dall'elenco usando l'opzione
-A
invece di
-a
. Poi testare il nome di ogni file dell'elenco per accertarsi che inizi con un punto. Un modo abbastanza semplice per farlo è tramite l'istruzione:

if [ ".${i#.} != ".${i}" ]; then
    echo "Rimuovo il file ${i}"
fi

Spiegazione nel caso non conoscessi l'espansione dei parametri: la stringa
".${i#.}"
è costituita da un punto seguito dal contenuto della variabile
$i
privato del più piccolo prefisso
.
(un punto). La seconda stringa,
".${i}"
, è costituita invece da un
.
seguito dal contenuto della variabile
$i
. È chiaro quindi che se
$i
contiene un valore che inizia con un punto allora le due stringhe saranno diverse e verrà eseguita la rimozione del file.

A parte questo, c'è da dire che se le directory nascoste (cioè quelle che iniziano con un punto) vanno eliminate senza controllarne il contenuto, allora lo script si può semplificare moltissimo. Considera poi che forse è meglio passare
$1/${i}
sia al comando
rm
che nella chiamate ricorsiva a
rmhid
.

Rispondi
Per rispondere a questa discussione devi prima effettuare il login.