PDA

View Full Version : [Bash scripting] Verificare data di modifica di un file


magix2003
23-08-2005, 08:13
Ciao,
sono ancora qua per rompervi con i miei problemi con il bash scripting. Questa volta il problema,imho, e' abbastanza ostico. Io devo creare uno script che controlli la data di modifica di un file e se e' inferiore ad un ora eseguire un operazione. Facendo una ricerca avevo pensato di usare l'opzione -atime di ls, pero' non sono riuscito a fare un ciclo if decente.
Avete consigli?
grazie

ilsensine
23-08-2005, 08:17
Più che ls, userei stat (v. stat --help, in particolare il parametro --format) così da avere direttamente un valore numerico utilizzabile.
Sposto in programmazione.

magix2003
23-08-2005, 08:35
Grazie, comunque ho trovato anche la funzione date -r file che fa la stessa cosa.
Adesso la mia domanda e': Come posso lavorare con le date?
Io vorrei fare una cosa cosi':

var = $data_di_oggi - $data_ultima_modifica
if var >= maggiore di un ora then
...
...
else
...
...

E' possibile?

ilsensine
23-08-2005, 08:40
Oppure (meglio) puoi usare direttamente find; ad es. questo:

find ./ -type f -mtime +<n> -exec <tuo script> {} \;

cerca dalla dir corrente tutti i file regolari (-type f) modificati prima di <n> giorni fa (puoi anche usare -mmin specificando i minuti; ad es. -mmin +10), e per ogni corrispondenza invoca un tuo script passando come parametro il file trovato. Puoi implementare la funzione da eseguire dentro lo script.

magix2003
23-08-2005, 09:00
Molto interessante,
l'unico problemino e' che teoricamente potrebbe trovarmi piu' file, gli posso dare anche il nome del file da cercare=?
Un altra domanda: a posto dello script per una funzione gli do il suo nome tipo:
-exec <funzione()> {} \;?
Ciao e grazie

ilsensine
23-08-2005, 09:07
Molto interessante,
l'unico problemino e' che teoricamente potrebbe trovarmi piu' file, gli posso dare anche il nome del file da cercare=?
Puoi dargli tutti i parametri di ricerca che find supporta, ovviamente.
Un altra domanda: a posto dello script per una funzione gli do il suo nome tipo:
-exec <funzione()> {} \;?

Temo di no, ma puoi aggirare il problema in questa maniera:

#!/bin/bash

(find [parametri...]) | while read fname
do
# fai quello che vuoi con "$fname"
done

Tra i parametri di find qui ovviamente non usi -exec.

magix2003
23-08-2005, 09:14
Grazie mille,
credo che questa soluzione potrebbe funzionare :D
Pero' ho ancora un problema provando a fare:

find ./ -type f -name psql -mtime +1;

In questa cartella

[root@probe3 tmp]# ls -la
totale 34372
drwxrwxrwt 10 root root 4096 23 ago 10:07 .
drwxr-xr-x 23 root root 4096 22 ago 15:27 ..
-rw-r--r-- 1 postgres postgres 208110 19 ago 09:15 a.a
-rw-r--r-- 1 root root 2753088 18 ago 00:59 ala
srwxrwxrwx 1 root root 0 3 ago 18:18 collect.pipe
-rw------- 1 root root 28 18 ago 09:35 crontab.XXXXCglLR7
-rw-r--r-- 1 root root 23327394 19 ago 10:41 det.det
drwxrwxrwt 2 root root 4096 19 ago 10:52 .esd
drwxrwxrwt 2 root root 4096 2 ago 15:45 .font-unix
drwx------ 2 root root 4096 19 ago 10:52 gconfd-root
srw-rw-rw- 1 root root 0 2 ago 15:46 .gdm_socket
drwxrwxrwt 2 root root 4096 19 ago 10:52 .ICE-unix
srwxr-xr-x 1 root root 0 2 ago 15:53 mapping-root
drwx------ 2 501 501 4096 10 ago 11:28 mc-gstefanoni
drwx------ 2 root root 4096 18 ago 17:54 mc-root
drwx------ 2 root root 4096 19 ago 10:52 orbit-root
-rw-r--r-- 1 root root 2753088 19 ago 02:08 prova
-rw-r--r-- 1 root root 2753088 19 ago 02:22 prova;
-rw-r--r-- 1 root root 421298 19 ago 09:52 prova.ciao
-rw-r--r-- 1 root root 0 22 ago 17:07 psql
-rw-r--r-- 1 root root 2753088 19 ago 02:17 script.out
srwxrwxrwx 1 postgres postgres 0 23 ago 10:03 .s.PGSQL.5432
-rw------- 1 postgres postgres 26 23 ago 10:03 .s.PGSQL.5432.lock
-r--r--r-- 1 root root 11 2 ago 15:46 .X0-lock
drwxrwxrwt 2 root root 4096 2 ago 15:46 .X11-unix

Non mi trova niente, ho provato anche cambiando il valore + n ma niente...


#!/bin/bash

(find [parametri...]) | while read fname
do
# fai quello che vuoi con "$fname"
done

Scusami ma fname e' inteso per il file name vero?
Ciao e grazie ancora

ilsensine
23-08-2005, 09:18
Grazie mille,
credo che questa soluzione potrebbe funzionare :D
Pero' ho ancora un problema provando a fare:

find ./ -type f -name psql -mtime +1;

In questa cartella

-rw-r--r-- 1 root root 0 22 ago 17:07 psql

Non mi trova niente, ho provato anche cambiando il valore + n ma niente...
Il file psql è stato modificato meno di 24 ore fa. Leggi la man page di find.


Scusami ma fname e' inteso per il file name vero?
E' una variabile bash, che conterrà il nome del file. Puoi chiamarla come vuoi.

magix2003
23-08-2005, 09:23
Ok o letto(spero di aver capito bene), quindi significa che se un file e' stato creato prima di 24 ore fa non posso usare questa funzione. Ma il mio problema e' proprio che devo verificare se il file e' stato creato prima di un ora.
Ciao e scusa per le mie grandi perplessita'

ilsensine
23-08-2005, 09:26
Allora usa -mmin e specifica i minuti, come è scritto nella manpage e come ti ho già suggerito :D

magix2003
23-08-2005, 09:28
Avevo gia' provato, ma guarda il risultato:

[root@probe3 tmp]# find ./ -type f -name psql -mmin +60;
./psql
You have new mail in /var/spool/mail/root
[root@probe3 tmp]# find ./ -type f -name psql -mmin +50;
./psql
[root@probe3 tmp]# find ./ -type f -name psql -mmin +65;
./psql
[root@probe3 tmp]# find ./ -type f -name psql -mmin +10;
./psql
[root@probe3 tmp]# find ./ -type f -name psql -mmin +1000;
./psql

Lo trova sempre....

ilsensine
23-08-2005, 09:31
Avevo gia' provato, ma guarda il risultato:

[root@probe3 tmp]# find ./ -type f -name psql -mmin +60;
./psql
You have new mail in /var/spool/mail/root
[root@probe3 tmp]# find ./ -type f -name psql -mmin +50;
./psql
[root@probe3 tmp]# find ./ -type f -name psql -mmin +65;
./psql
[root@probe3 tmp]# find ./ -type f -name psql -mmin +10;
./psql
[root@probe3 tmp]# find ./ -type f -name psql -mmin +1000;
./psql

Lo trova sempre....
Certo tutte quelle corrispondenze sono soddisfatte. 1000 minuti sono meno di 17 ore; il file psql ha circa 18 ore e mezzo in questo momento.

ilsensine
23-08-2005, 09:35
Se vuoi trovare i file modificati da non più di un'ora, utilizza -mmin -60. Puoi anche specificare un intervallo:
find -mmin +60 -mmin -120 trova tutti i file modificati tra una e due ore fa.

magix2003
23-08-2005, 09:35
Scusami sono proprio un idiota, comunque se io volessi eseguire uno script solo quando il file ha piu' di un ora dovrei modificare il ciclo while o?


#!/bin/bash

(find [parametri...]) | while read fname
do
# fai quello che vuoi con "$fname"
done

Qualcosa del tipo:
while read <> fname?
Ciao e grazie mille

ilsensine
23-08-2005, 09:38
Scusami sono proprio un idiota, comunque se io volessi eseguire uno script solo quando il file ha piu' di un ora dovrei modificare il ciclo while o?

Qualcosa del tipo:
while read <> fname?
Ciao e grazie mille
No la ricerca è effettuata tutta dal find, che scrive le corrispondenze su stdout. In pipe, redirigi lo stdout al ciclo while, che si occupa di leggere l'input riga per riga mettendole di volta in volta nella variabile specificata.

magix2003
23-08-2005, 09:48
Mi sa che non ho ancora capito e non mi sono spiegato bene.
Io ho provato a eseguire questo script:

#!/bin/bash
(find ./ -type f -name psql -mmin +1000;)|while read psql
do
echo "sto leggendo"
done

E in output mi ha dato l'echo correttamente. Ma io vorrei che se il file e' piu vecchio di un ora(cioe' -mmin +1440) mi scriva sto leggendo, cioe' il contrario di adesso
ciao e scusami sempre di piu

ilsensine
23-08-2005, 09:53
Mi sa che non ho ancora capito e non mi sono spiegato bene.
Io ho provato a eseguire questo script:

#!/bin/bash
(find ./ -type f -name psql -mmin +1000;)|while read psql
do
echo "sto leggendo"
done

E in output mi ha dato l'echo correttamente. Ma io vorrei che se il file e' piu vecchio di un ora(cioe' -mmin +1440) mi scriva sto leggendo, cioe' il contrario di adesso
ciao e scusami sempre di piu
Hai specificato: "se il file è più vecchio di 1000 minuti, scrivi sto leggendo". E infatti lui scrive, in quanto psql è più vecchio di 1000 minuti.
nb un'ora sono 60 minuti, non 1440 ;)

magix2003
23-08-2005, 09:57
Si questo lo ho capito io vorrei che la condizione fosse se piu vecchio di un giorno cioe' 1440 esegui, mentre adesso e' se piu' giovane di un giorno esegui. Hai capito cosa intendo?

ilsensine
23-08-2005, 10:04
Certo che -mmin +1440 non ti restituisce nulla, psql _ancora_ non è vecchio di un giorno (24 ore).
Aspetta fino alle 5 di questo pomeriggio e vedrai ;)

(nb se vuoi proprio intendere "i file di ieri", a prescindere dalle ore di differenza, nella info page trovi la soluzione ;) )

magix2003
23-08-2005, 10:12
Avevi ragione tu ;)
Pero' io vorrei fare in modo che controlli se e' minore o = ad un ora....
Bye

ilsensine
23-08-2005, 10:13
Pero' io vorrei fare in modo che controlli se e' minore o = ad un ora....

...? Ad un'ora da _adesso_ o ad un'ora da...quando?

magix2003
23-08-2005, 10:18
I processi sarebbero questi:

Lancio lo script
Controllo se il file e' stato creato meno di un ora fa dal momento del lancio dello script
Se si eseguo dei comandi altrimenti no

Spero di essere stato piu chiaro adesso, il problema che neanche io ho le idee molto chiare...

ilsensine
23-08-2005, 10:24
Spero di essere stato piu chiaro adesso, il problema che neanche io ho le idee molto chiare...
Non molto, visto che mischi "creato" con "modificato", e "prima di un'ora fa" con "dopo un'ora fa" passando per "un giorno fa"...

Puoi riordinare un attimo le idee e richiedere _esattamente_ cosa vuoi fare?

magix2003
23-08-2005, 10:27
Si lo so sono stato "un po'" confuso, comunque questo e' il riassunto esatto:

I processi sarebbero questi:

1. Lancio lo script
2. Controllo se il file e' stato creato meno di un ora fa dal momento del lancio dello script
3. Se si eseguo dei comandi altrimenti no

ilsensine
23-08-2005, 10:32
Ok "meno di un'ora dal lancio dello script" è abbastanza complicato da ottenere; puoi approssimarla con "meno di un'ora fa" visto che l'esecuzione dello script è abbastanza veloce. Il tutto si riduce in

#!/bin/bash
(find ./ -type f -name psql -mmin -60)|while read fname
do
echo "sto leggendo $fname"
done

magix2003
23-08-2005, 10:39
Grazie mille cosi' funziona!!!!
:ave:

ilsensine
23-08-2005, 12:21
Non per mettere il dito nella piaga, ma te lo avevo già detto ;)

Se vuoi trovare i file modificati da non più di un'ora, utilizza -mmin -60. Puoi anche specificare un intervallo:
find -mmin +60 -mmin -120 trova tutti i file modificati tra una e due ore fa.

Matrixbob
23-08-2012, 14:35
Come faccio a prendere il solo nome del file e non tutto il path assoluto?
Volevo spostare i file vecchi automaticamente in un'altra cartella, ma così va in botta... :(

(find /in/ -type f -name 'PIPPO_*' )|while read fname
do
echo "sto muovendo $fname"
mv $fname /in/file_bak/$fname
done

Gimli[2BV!2B]
23-08-2012, 14:45
Credo possa andare così:(find /in/ -type f -name 'PIPPO_*' )|while read fname
do
echo "sto muovendo \"$fname\""
mv "$fname" /in/file_bak/$(basename "$fname")
done
P.S. se ci sono spazi nel nome non può funzionare, ora aggiungo anche questa "protezione".

Gimli[2BV!2B]
23-08-2012, 14:54
La soluzione più veloce che mi è venuta in mente è una variabile di appoggio:(find /in/ -type f -name 'PIPPO_*' )|while read fname
do
echo "sto muovendo \"$fname\""
FILENAME="$(basename "$fname")"
mv "$fname" "/in/file_bak/$FILENAME"
done

Matrixbob
23-08-2012, 15:08
;37982695']Credo possa andare così:(find /in/ -type f -name 'PIPPO_*' )|while read fname
do
echo "sto muovendo \"$fname\""
mv "$fname" /in/file_bak/$(basename "$fname")
done
P.S. se ci sono spazi nel nome non può funzionare, ora aggiungo anche questa "protezione".

Questa al secondo giro era come se andasse ancora + in profondità e li trovava nella cartella di bak

sto muovendo "/in/file_bak/PIPPO_00050000003F6EF0"

Dovrei escludere le sottodirectory.

Matrixbob
23-08-2012, 15:44
-maxdepth 0 non funziona :( è un unix hp mi sa :(

Gimli[2BV!2B]
23-08-2012, 23:16
Ma la cartella di backup dev'essere per forza una sotto cartella di quella da elaborare? Non è molto comodo né mi sembra sicurissimo...

Riepilogando:

cerchi file che hanno un nome con un certo pattern
questi file li devi cercare in una cartella
*non* devi cercarli in nessuna sotto-cartella
li devi spostare in una sotto-cartella, non preoccupandoti se già presenti


In tal caso tolgo find:
SAVEIFS=$IFS
IFS=$(echo -en "\n\b")

for FILE in $(ls "/in/PIPPO_*") ; do
[ -d "$FILE" ] && continue

echo "sto muovendo \"$FILE\""
FILENAME="$(basename "$FILE")"
mv "$FILE" "/in/file_bak/$FILENAME"
done

IFS=$SAVEIFS

Matrixbob
24-08-2012, 08:13
;37985222']Ma la cartella di backup dev'essere per forza una sotto cartella di quella da elaborare? Non è molto comodo né mi sembra sicurissimo...

Riepilogando:

cerchi file che hanno un nome con un certo pattern
questi file li devi cercare in una cartella
*non* devi cercarli in nessuna sotto-cartella
li devi spostare in una sotto-cartella, non preoccupandoti se già presenti


In tal caso tolgo find:
SAVEIFS=$IFS
IFS=$(echo -en "\n\b")

for FILE in $(ls "/in/PIPPO_*") ; do
[ -d "$FILE" ] && continue

echo "sto muovendo \"$FILE\""
FILENAME="$(basename "$FILE")"
mv "$FILE" "/in/file_bak/$FILENAME"
done

IFS=$SAVEIFS
Grazie, ragazzi di avermi seguito.
Si tutto corretto, ma in aggiunta avrei dovuto fare un controllo sulla vecchiaia del file (es 5gg) e quindi l'ls mi veniva scomodo.
Alla fine ho risolto con questo:

(find /in/PIPPO_* -prune -type f -mtime +5)|while read fname
do
echo "sto muovendo \"$fname\""
mv /in/$(basename "$fname") /in/portafoglio_bak/$(basename "$fname")
done
, come sintassi del find mi rimane un po ostica, ma sembra funzionare bene.