PDA

Visualizza versione completa : Script batch per copia e catalogazione


borgata
20-02-2016, 21.06.28
Mi serve un piccolo script batch, normalmente lo farei da solo ma questo è un periodo un po' pieno e sto continuamente rimandando.
Al che mi son detto: metti il caso che qualche buon samaritano qui su WT possa darmi una manina...

Vediamo quindi di riassumere la situazione:

Per motivi di spazio, non posso copiare dei dati dal disco principale a quello di backup, per cui la geniale soluzione :D è stata quella di copiare solo la struttura delle directory e i file di piccole dimensioni, sostituendo quelli più grandi.

Pensavo quindi ad una cosa di questo tipo:
- piazzo il file batch da qualche parte e questo agisce sulla directory corrente e su tutte le sottodirectory
- usa xcopy per copiare
- tra le variabili del file, stabilisco una dimensione massima per i file che devono essere copiati
- avviato lo script, inizia la copia

Ora, i punti da decidere sono due:

1) cosa fare con i file grandi
2) gestire eventualmente utilizzi successivi

1) I file grandi
Fondamentalmente, pensavo ad alcune soluzioni:
- anzichè copiare il file, crearne uno con lo stesso nome ma vuoto
- come sopra, ma contenente all'interno i dati del file originale (tipo dimensione, data, e qualsiasi altra cosa possa essere utile, pochi dati comunque). Ovviamente questa soluzione è preferibile alla prima.
- un file di testo con .txt aggiunto dopo il nome del file (quindi miofile.png diventerebbe miofile.png.txt)
- come sopra, con in più i dati
- creare un file di testo (mancanti.txt) contenente la lista dei file non copiati
- come sopra, ma contenente sia la lista che alcune caratteristiche

2) Riuso del batch
Un riuso del batch ovviamente implicherebbe il conflitto tra i file già copiati e il nuovo flusso di copia. Come gestirlo?
- non lo gestisco, i nuovi file sovrascrivono i vecchi. Facile, ma decisamente poco ottimizzato.
- copio solo i file nuovi. Non difficile, ma rischio di tenermi roba vecchia.
- copio i file nuovi e controllo i vecchi, se i nuovi sono più recenti (o semplicemente diversi) li sostituisco, altrimenti non faccio nulla.

Qualcuno vuole cimentarsi nell'impresa? :D

borgata
22-02-2016, 13.23.07
Mi sa che ho chiesto troppo eh! :D

In alternativa un programma portable di sincronizzazione che permetta di fare lo stesso?

LoryOne
22-02-2016, 16.14.30
Perchè xcopy e non copy ?
Da quel che mi pare di capire, dovresti ricreare la sottostruttura delle cartelle in modo ricorsivo, per ogni file incluso nelle sottocartelle verificarne la dimensione, acquisirne alcune caratteristiche, scrivere un file sostitutivo dell'originale oppure copiare l'originale...

Certo che xcopy ti consentirebbe di creare un percorso come .\a\b\c, mentre con copy saresti costretto a lanciare md a, md .\a\b, md .\a\b\c...

borgata
23-02-2016, 00.03.49
Grazie LoryOne.

Esatto. XCopy ha qualche funzionalità in più, l'ho usato per fare qualche altro scriptino e fa il suo dovere.
Naturalmente non è un dogma, se si vede che lo script lavora meglio con altri comandi, non c'è ragione per non usarli.

LoryOne
23-02-2016, 08.51.12
...Infatti pensavo ad una cosa del genere:

Echo off
set "filename=\*.*"
for %%A in (%filename%) do (
echo.Il nome file completo e' %%~fA
echo.Il nome del file e' %%~nA
echo.Il suo percorso e' %%~pA
echo.Il suo attributo temporale e' %%~tA
echo.La sua estensione e' %%~xA
echo.La dimensione di "%%A" e' %%~zA bytes
)

...quasi fatto

borgata
23-02-2016, 09.16.06
Grazie! ;)
Per la ricorsività come pensi di risolvere? Manualmente?

LoryOne
23-02-2016, 09.25.11
No.
C'è un altro for solo sulle sottodirectories che recupera 'dir \ /s /b /ad /on'
Ogni singola voce recuperata da dir ordinata per nome, passa alla creazione della cartella, poi allo script precedente per la lista dei files...
In questo modo, visto che è su proprietà di alcuni dei files che vuoi agire, si ha uno script che compie una scrematura sul contenuto in base alle tue esigenze ed in modo ricorsivo

LoryOne
23-02-2016, 17.25.03
@echo off
for /f "tokens=*" %%A in ('dir \ /s /b /ad /on') do (
for %%B in ("%%A\*.*") do (
if %%~zB gtr 5000000 (
echo.Cartella %%A
echo.Il nome file completo e' %%~fB
echo.La sua dimensione e' %%~zB bytes
)
)

)

borgata
23-02-2016, 19.41.55
Sta procedendo vedo! ;)
Occhio che in questo modo però estrapola i percorsi di tutta l'unità, non solo quelli della directory corrente e sottodirectory. Dovresti mettere . al posto di \ nel comando del for.

Piuttosto nel secondo for stai filtrando le directory con quell' *.* o sbaglio?
Ci potrebbero essere directory con il punto nel nome e file senza estensione. mi sa che bisogna filtrare in base all'attributo.

xilo76
23-02-2016, 19.49.36
Io ho usato powershell...
In $Destinazione metterai la cartella di destinazione.
In $DimensioneMassimaDeiFile metterai la dimensione massima che preferisci (in byte).
Poi piazzi il file .ps1 nella cartella desiderata e lo fai partire.
Pare funzionare, ma mi modifica il nome di tre file nella cartella di destinazione.
Quindi qualche errore c'è!

function opera () {
FOR ($i=0; $i -lt $VetFile.Length; $i++) {
NV -Name "LineaFile$i"
SV -Name "LineaFile$i" -Value $VetFile.GetValue($i)
NV -Name "LineaDim$i"
SV -Name "LineaDim$i" -Value $VetDim.GetValue($i)
$t1 = GV -Name "LineaFile$i" -valueonly
$t2 = GV -Name "LineaDim$i" -valueonly
$t2 = ([convert]::ToInt32($t2,10))
if ($t2 -isnot [int]) {$t2 = 0}
if ($t1 -eq "") { continue }
if (!($t1 -eq "")) { if ($t2 -ge 1) { if ($t2 -lt $DimensioneMassimaDeiFile) {
copy "$t1" ("$Destinazione"+"\"+$t1.trimstart("$Partenza"))
continue }}}
if ($t2 -ge $DimensioneMassimaDeiFile) {
$t1 = $t1.trimstart("$Partenza")
$t1 = ("$Destinazione"+"\"+"$t1")
fsutil file createnew "$t1" 0
continue }
$t1 = $t1.trimstart("$Partenza")
$t1 = ("$Destinazione"+"\"+"$t1")
md $t1
RV -Name "LineaFile$i"
RV -Name "LineaDim$i"
RV -Name $t1
RV -Name $t2 }}



$Destinazione = "C:\total"
$DimensioneMassimaDeiFile = 14



$Partenza = (Get-Item -Path ".\" -Verbose).FullName
$File = "c:\users\$env:username\desktop\lista.txt"
$Dimensione = "c:\users\$env:username\desktop\dimensioni.txt"
$test = !(test-path $Destinazione)
if ($test) {md $Destinazione}
GCI -Path ".\" -recurse | sort fullname | FT -property fullname -HideTableHeaders | Out-File $File
GCI -Path ".\" -recurse | sort fullname | FT -property length -HideTableHeaders | Out-File $Dimensione
$VetFile = (Get-Content -Path $File).trimend(" ")
$VetDim = ((Get-content -path $Dimensione).trimend(" ")).trimstart(" ")
$VetFile | Out-File $File
$VetDim | Out-File $Dimensione
opera
del $File
del $Dimensione
RV -Name Partenza
RV -Name test
RV -Name VetFile
RV -Name VetDim
RV -Name Destinazione
RV -Name DimensioneMassimaDeiFile
RV -Name File
RV -Name Dimensione

LoryOne
23-02-2016, 20.05.54
Sta procedendo vedo! ;)
Occhio che in questo modo però estrapola i percorsi di tutta l'unità, non solo quelli della directory corrente e sottodirectory. Dovresti mettere . al posto di \ nel comando del for.

Quello che ho postato è solo un esempio, se vuoi lo scheletro del programma.
Al posto del '\' ci andrà un parametro da riga di comando, oppure una variabile che imposterai con un set...
Non so esattamente cosa ne vorrai fare, ma da quel che ho capito tutto ruota attorno ai files contenuti in cartelle.


Piuttosto nel secondo for stai filtrando le directory con quell' *.* o sbaglio?
Ci potrebbero essere directory con il punto nel nome e file senza estensione. mi sa che bisogna filtrare in base all'attributo.

Si beh...a dire il vero non ho testato a fondo, però poco ci vuole a fargli fare un'altra dir...
Si può usare anche un xcopy /L, però alla fine mostra una riga che non c'entra nulla,mentre con dir /b vai sul sicuro.

borgata
23-02-2016, 23.18.06
Per il primo punto, sostituire / con . dovrebbe essere sufficiente.
Per il secondo... sicuramente potrebbe funzionare con un "if", però forse si risolve più facilmente con il giusto parametro del comando.

Secondo te conviene strutturare lo script in due parti (prima creo i percorsi, poi copio i contenuti), oppure si fa tutto in uno?

LoryOne
24-02-2016, 08.08.19
Secondo me dovresti iniziare copiando il solo contenuto della cartella e poi quello delle sottocartelle.
Così com'è strutturato, però, presenta un problema:
Se non figurano cartelle in quella che passi come parametro, lo script non fa nulla.
C'è qundi da usare un "for %%B in ("%1\*.*") do ..." prima di tutto.
I files in enumerazione hanno tutti l'attributo archive attivo (non directory), quindi anche se non presentano estensione vengono presi in considerazione.
Basterebbe un "attrib +h nomefile" per non enumerarlo, ma non so se devi prendere in esame anche questa casistica specifica.
In ogni caso, con dir agisci come meglio credi.

borgata
25-02-2016, 01.01.58
Vero, in effetti il primo for elenca le sottocartelle, quindi per la cartella principale occorrerà gestire un for per i file a parte.
Non ti seguo bene sulla questione attributi, devo un attimo vedere come funziona il comando.

@xilo
Ti ho risposto per messaggio privato!

LoryOne
25-02-2016, 14.26.54
Funziona così, ma verifica pure, ci mancherebbe !
Supponiamo che nella cartella Numeri siano presenti: una cartella Uno, un file Uno.cifra ed un file due
Numeri
|------>Uno
|------>Uno.cifra
|------>due
L'enumerazione elencherà Uno.cifra e due, scartando Uno perchè directory
Modificando l'attributo di due con hidden (attrib +h due), due non verrà più elencato.

Esempio:

cd \
C:\>attrib
C:\123.tif
A SHR C:\BOOT.INI
A SHR C:\Bootfont.bin
A SH C:\BOOTSECT.DOS
A C:\CONFIG.SYS
H C:\IO.SYS
A SHR C:\MSDOS.SYS
A SHR C:\NTDETECT.COM
A SHR C:\ntldr
A SH C:\pagefile.sys
C:\SYSLEVEL.IBM


Restituzione:
Il nome file completo e' C:\123.tif
Il nome file completo e' C:\CONFIG.SYS
Il nome file completo e' C:\SYSLEVEL.IBM

Prende in esame combinazione attributo nullo, A,R.
Forse S, sicuramente non H.

borgata
25-02-2016, 17.37.06
Per quel che serve a me, deve copiare tutti i file (eccetto i file grandi che hanno un trattamente diverso), file nascosti compresi.
E ricreare la struttura completa delle cartelle (per la quale ero indeciso se crearla prima di iniziare a copiare i file o durante).

LoryOne
25-02-2016, 20.51.42
Allora devi ricorrere a dir per elencare anche i files nascosti.
La tua indecisione, non pregiudica lo script: Puoi creare prima tutta la struttura, poi copiare i files, oppure fare una e l'altro contemporaneamente.
Ordinando le cartelle per nome sei sicuro di non incorrere in errori di creazione percorso, salvo quello di percorso/file già presente in destinazione in caso di riutilizzo dello script...ma la gestione delle eccezioni la vedrai mano a mano che lo script prenderà corpo da quell'esempio di base, gestendo opportunamente gli ErrorLevel per i quali quasi tutti i comandi della shell sono predisposti a fornire come indicativi specifici, per ogni eccezione numerata (Ossia, il classico function return del C).
E' molto probabile che anche xcopy, visto che da tempo è entrata a far parte del set di comandi della shell già dai tempi di MS-DOS, restituisca un ErrorLevel diverso in funzione dell'eccezione riscontrata.

borgata
25-02-2016, 22.51.24
Avevo fatto una prova veloce con un pezzetto del tuo script e mi era parso che vedesse tutto, sia file nascosti che di sistema.
Per gli errori, inizialmente credo lo script sarà molto spartano (con meno situazioni che possano generare errore possibile), poi farò un bel file di log, giusto per sicurezza.