[Script] spostare file

franbisc
1   #! /bin/sh
2   if (test $# -ne 2) then
3   echo "Uso: $0 estensione direttorio"
4   exit -1
5   fi
6   if (test ! -d $2) then
7   echo "Il direttorio $2 non esiste, adesso lo creo"
8   mkdir $2
9   fi
10  echo "Dimmi la parola che devo cercare: "
11  read parola
12  for i in *.$1
13  do
14  echo "Esamino il file $i"
15  if (grep $parola $i) then
16  echo "Sposto $i in $2"
17  mv $i $2
18  fi
19  done


Premesso che sono alle primissime armi,ho capito che lo script serve a spostare in un direttorio specificato dall’utente tutti i file con una certa estensione (anch’essa specificata dall’utente) e che contengono una certa parola (che lo script chiede all’utente),e se il direttorio specificato dall’utente non esiste, viene creato dallo script.
Le cose che non mi sono chiare sono :
riga 2 :
if (test $# -ne 2)
, che significa -ne? Cosa indica il 2?
riga 6 :
if (test ! -d $2)
...tutta :?

Inoltre ora mi si richiede di aggiungere allo script la possibilità di invocarlo con due eventuali opzioni -s e -n (ad es. mioscript [-s] [-n] : la prima opzione consente all’utente di specificare se desidera la sovrascrittura (-s) dei file già contenuti nel direttorio destinazione, mentre la seconda opzione gli permette di specificare che la parola introdotta da tastiera deve (default) oppure non deve (-n) essere presente nei file esaminati.
ovviamente non so da dove partire... :roll:

Risposte
Studente Anonimo
Studente Anonimo
"Mifert4":

Le cose che non mi sono chiare sono :
riga 2 :
if (test $# -ne 2)
, che significa -ne? Cosa indica il 2?

$#
è una variabile che contiene il numero degli argomenti passati allo script.
-ne
è un operatore del comando
test(1)
e signfica "non uguale a". Quindi la condizione dell'if è verificata se il numero degli argomenti sulla riga di comando non è uguale a 2.


riga 6 :
if (test ! -d $2)

se il parametro (della riga di comando)
$2
non (operatore
!
) è una directory (
-d
) allora...

Inoltre ora mi si richiede di aggiungere allo script la possibilità di invocarlo con due eventuali opzioni -s e -n [...]
ovviamente non so da dove partire... :roll:

Ci sono vari modi, prova a guardare il comando
getopts
della shell. Comunque, visto che usi Linux, trovi maggiori informazioni nella manpage della shell (comando man sh, anche se penso che tu lo sappia questo). :)

franbisc
#! /bin/sh
if (test ! -d $2) then
echo "Il direttorio $2 non esiste, adesso lo creo"
mkdir $2
fi
getopts first
getopts second
if (test $first = "-s" -o $second = "-s")
cp -r $i $2
rm -rf $i $2
fi
if(test first ! "-n" | second ! "-n")
echo "Sono da spostare i file che contengono la parola...: "
read parola
for i in *.$1
do
echo "Esamino il file $i"
if (grep $parola $i) then
echo "Sposto $i in $2"
else
echo "Sono da spostare i file che contengono la parola...: "
read parola
for i in *.$1
do
echo "Esamino il file $i"
if (grep ! $parola $i) then
echo "Sposto $i in $2"
fi
done


Ho tentato di fare qualcosa,ma ovviamente sono troppe le cose che non so.Ad esempio l'operazione di sovrascrittura credo proprio che sia grossolana se non completamente sbagliata...

Studente Anonimo
Studente Anonimo
Ciao, ti do qualche suggerimento.

[list=1]
[*:3bkfj04x]getopts
ti conviene usare un ciclo while per scandire gli argomenti con questa struttura

while getopts "ns" opzione
do
    case "${opzione}" in
        s) # opzione -s, fai qualcosa
        n) # opzione -n, fai qualcosa
        ?) # opzione sconosciuta
done

[/*:m:3bkfj04x]
[*:3bkfj04x] opzione -s (sovrascrittura)
Puoi ad esempio impostare a "" (stringa vuota) una variabile di nome sovrascrivi, che imposterai/cambierai a "-f" nel
case
precedente quando ${opzione} è uguale a
s
, cioè l'utente ha richiesto la sovrascrittura dei file.
In questo modo, quando poi andrai a a copiare i file, passerai questa variabile sovrascrivi al comando cp.
[/*:m:3bkfj04x]
[*:3bkfj04x] opzione -n (non presente)
Stesso discorso di prima. Definisci all'inizio del file una variabile di nome presente ad esempio con un certo valore, che modificherai poi nel
case
se viene incontrata l'opzione -n
Quale valore assegnare di default a questa variabile? Be', puoi sfruttare le opzioni di grep, in modo da fargli selezionare a lui quali file contengono e quali non contengono la parola da cercare. Precisamente

    [*:3bkfj04x]-l (elle) fa in modo che grep dia in output i nomi dei file che contengono la parola[/*:m:3bkfj04x]
    [*:3bkfj04x]-L fa invece in modo che grep dia in output i nomi dei file che NON contengono la parola.[/*:m:3bkfj04x][/list:u:3bkfj04x]
    Quindi all'inizio puoi assegnare alla variabile presente il valore -l, per poi eventualmente cambiarlo in -L se è presente l'opzione -n.[/*:m:3bkfj04x]
    [*:3bkfj04x] copia/sovrascrittura dei file
    Lo puoi fare ad esempio con un ciclo for sui file forniti da egrep, in questo modo

    for f in $(grep ${presente} *.$1)
    do
         cp ${sovrascrivi} ${f} $2
    done
    

    magari aggiungendo un preventivo controllo sull'esistenza di un analogo file nella directory di destinazione nel caso l'opzione sovrascrivi sia assente, in modo da saltarlo o segnalare la cosa tramite un messaggio.[/*:m:3bkfj04x][/list:o:3bkfj04x]

    HTH

    P.S. Ricordati inoltre di controllare che siano stati passati il nome della directory di destinazione e l'estensione.

franbisc
Nuovo tentativo,ma non fa ancora quello che dovrebbe :(

#! /bin/sh
if (test $# -lt 2) then
  echo "Uso: $0 estensione direttorio"
  exit -1
fi
if (test $# -eq 4) then
  if (test ! -d $4) then
    echo "Il direttorio $4 non esiste, lo creo"
    mkdir $4
  fi
fi
if (test $# -eq 3) then
  if (test ! -d $3) then
    echo "Il direttorio $3 non esiste, lo creo"
    mkdir $3
  fi
fi
if (test $# -eq 2) then
  if (test ! -d $2) then
    echo "Il direttorio $2 non esiste, lo creo"
    mkdir $2
  fi
fi
sovrascrivi=""
presente="-l"
while getopts "ns" opzione
do
  case "${opzione}" in
      s) $sovrascrivi= "-f";;
      n) $presente= "-L";;
      ?) echo "Opzione sconosciuta"
         exit -1
  esac
done
echo "Parola che devo cercare...? "
read parola
for i in *.$1
  do
    echo "Esamino il file $i"
    for i in $(grep ${presente} $parola *.$1)
     do
       cp ${sovrascrivi} ${f} $2
    done
done


Al di la del fatto che l'operazione di spostamento non tiene ancora conto del numero di argomenti,perchè non mi sembrava "normale" fare ogni volta il controllo che ho fatto qui
if (test $# -eq 4) then...
if (test $# -eq 3) then...
if (test $# -eq 2) then...

Studente Anonimo
Studente Anonimo
"Mifert4":
Nuovo tentativo,ma non fa ancora quello che dovrebbe

Invece io direi che ci sei quasi. Devi solo rivedere l'ordine in cui esegui le varie istruzioni, aggiungere una parte che controlli quante opzioni sono stati richieste e migliorare l'ultimo blocco, quello che esegue la selezione dei file da copiare e poi li copia.

I suggerimenti in spoiler:

inoltre se ad esempio invoco lo script con l'opzione -h (una a caso) invece di scrivermi il messaggio di errore e invocare exit mi appare il messaggio di errore della shell

Sì, in questo caso per evitarne la stampa basta che fai precedere l'elenco delle tue opzioni da un due punti, quindi l'istruzione sarà

while getopts ":ns" opzione

franbisc
#! /bin/sh
if (test $# -lt 2) then
  echo "Uso: $0 estensione direttorio"
  exit -1
fi
sovrascrivi=""
presente="-n"
while getopts ":ns" opzione
do
  case "${opzione}" in
      s) $sovrascrivi= "-f";;
      n) $presente= "-L";;
      /?) echo "Opzione sconosciuta"
         exit -1;;
  esac
done
shift $OPTIND
if (test ! -d $2) then
  echo "Il direttorio $2 non esiste, lo creo"
  mkdir $2
fi
echo "Parola che devo cercare...? "
read parola
for i in $(grep ${presente} $parola *.$1)
  do
  cp ${sovrascrivi} ${i} $2
done


Non mi è chiaro l'uso di OPTIND, ma a giudicare dal messaggio di errore("grep: *.file: File o directory non esistente
") lo shift non fa effetto...

All'interno di questo ciclo for sarà utile ignorare la copia del file quando l'utente non ha richiesto la sovrascrittura e il file di destinazione esiste già

Non è quello che già succede usando cp in quel modo?

Studente Anonimo
Studente Anonimo
Ho aggiunto qualche commento (senza correggerlo) al tuo codice

#! /bin/sh
# questo blocco va spostato più avanti (vedi oltre)
if (test $# -lt 2) then
  echo "Uso: $0 estensione direttorio"
  exit -1
fi
# "sovrascrivi" è meglio inizializzarla a -n
sovrascrivi=""
# "presente" invece a -l (com'era prima)
presente="-n"
while getopts ":ns" opzione
do
  case "${opzione}" in
      s) $sovrascrivi= "-f";;
      n) $presente= "-L";;
      # va usato uno slash \ non un backslash /
      /?) echo "Opzione sconosciuta"
         exit -1;;
  esac
done
# OPTIND è una variabile (il cui valore iniziale è 1)
# incrementata da getopts ogni qual volta trova un'opzione
# tra quelle definite (-n e -s).
# Quindi...
#
# Inoltre devi aggiungere un controllo sul risultato del
# calcolo precedente, di modo che venga eseguito lo shift
# soltanto se tale risultato  > 0
shift $OPTIND
# il blocco iniziale va spostato qui
#
if (test ! -d $2) then
  echo "Il direttorio $2 non esiste, lo creo"
  mkdir $2
fi
echo "Parola che devo cercare...? "
read parola
for i in $(grep ${presente} $parola *.$1)
  do
  # come detto potresti aggiungere un controllo (if)
  # per ignorare i file che esistono già nella
  # directory di destinazione, nel caso l'utente
  # non abbia specificato l'opzione -n, in questo
  # modo eviti di eseguire inutilmente il programma cp
  cp ${sovrascrivi} ${i} $2
done

"anonymous_be1147":
All'interno di questo ciclo for sarà utile ignorare la copia del file quando l'utente non ha richiesto la sovrascrittura e il file di destinazione esiste già

Non è quello che già succede usando cp in quel modo?

Certamente, però come detto sarebbe utile (non obbligatorio) in modo da evitare di eseguire inutilmente il programma copy, ma anche senza tale controllo il programma funziona... o almeno si spera. :-D

Luc@s
Domanda/curiosità... come mai usi
test
e non le
 []
per le verifiche?


P.S: direttorio non si può proprio sentire :shock:

franbisc
@anonymous_be1147 Ora ci provo...ce la posso fare :lol:

"Luc@s":
Domanda/curiosità... come mai usi
test
e non le
 []
per le verifiche?

Era già impostato così... :)


"Luc@s":

P.S: direttorio non si può proprio sentire :shock:

:-D hai ragione...ma è l'influenza del professore...

franbisc
Non ce la posso fare.
Mi è venuto in mente questo,ma non so se sbaglio la sintassi o altro...
n=$OPTIND-1
if (test n -gt 0)
  shift $n
fi 

Studente Anonimo
Studente Anonimo
"Mifert4":
Non ce la posso fare.

Mi dispiace contraddirti, ma l'hai praticamente finito. :)

Mi è venuto in mente questo,ma non so se sbaglio la sintassi o altro...
n=$OPTIND-1
if (test n -gt 0)
  shift $n
fi 

Esattamente è un problema di sintassi. Se scrivi
n=$OPTIND-1
, alla variabile n viene assegnato il valore di OPTIND, seguito da un segno meno e poi da un 1, cioè una stringa di caratteri. Invece per eseguire dei calcoli aritmetici devi usare o il comando expr(1) oppure la cosiddetta espansione aritmetica
$(( ))
, cioè scrivere
n=$((${OPTIND}-1))
.

Ora non ti resta che preparare dei test per controllare a fondo lo script. :smt023

franbisc
C'erano altri errori: nell'if in questione dopo la parentesi non ci ho messo il then...e nel case: nelle lettere in parentesi (n ed s) ci andava il ' - ' d'avanti.
Ora comunque funziona...GRAZIE MILLE :D

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