Ho bisogno di sapere che prima di ogni tentativo di fare qualsiasi cosa con tale file.Come controllare la riga di comando se un determinato file o directory è bloccato (utilizzato da qualsiasi processo)?
risposta
Non sei sicuro di directory bloccate
Ma rilevare se un file è in fase di scrittura da un altro processo non è difficile.
@echo off
2>nul (
>>test.txt echo off
) && (echo file is not locked) || (echo file is locked)
Io uso il seguente script di test da un'altra finestra per posizionare un blocco sul file.
(
>&2 pause
) >> test.txt
Quando eseguo il 2 ° script da una finestra e quindi eseguire il primo script da una seconda finestra, ottengo il mio messaggio "bloccato". Dopo aver premuto <Enter>
nella prima finestra, ottengo il messaggio "sbloccato" se rieseguo il primo script.
Spiegazione
Ogni volta che l'output di un comando viene reindirizzato a un file, il file ovviamente deve essere aperta per l'accesso in scrittura. La sessione CMD di Windows tenterà di aprire il file, anche se il comando non produce alcun output.
L'operatore di reindirizzamento >>
apre il file in modalità di aggiunta.
Quindi >>test.txt echo off
tenterà di aprire il file, non scrive nulla sul file (presupponendo che echo sia già disattivato) e quindi chiude il file. Il file non è stato modificato in alcun modo.
La maggior parte dei processi blocca un file ogni volta che apre un file per l'accesso in scrittura. (Esistono chiamate di sistema del sistema operativo che consentono l'apertura di un file per la scrittura in una modalità condivisa, ma non è quella predefinita). Quindi se un altro processo ha già "test.txt" bloccato per la scrittura, il reindirizzamento fallirà con il seguente messaggio di errore inviato a stderr - "Il processo non può accedere al file perché è utilizzato da un altro processo.". Inoltre verrà generato un codice di errore in caso di errore di reindirizzamento. Se il comando e il reindirizzamento hanno esito positivo, viene restituito un codice di successo.
Aggiungere semplicemente 2>nul
al comando non impedirà il messaggio di errore perché reindirizza l'output dell'errore per il comando, non il reindirizzamento. Ecco perché accludo il comando tra parentesi e poi reindirizzo l'output dell'errore a nul al di fuori del paren.
Quindi il messaggio di errore è effettivamente nascosto, ma il codice di errore è ancora propagato al di fuori del paren. Gli operatori standard di Windows &&
e ||
vengono utilizzati per rilevare se il comando all'interno del paren ha avuto esito positivo o negativo.Presumibilmente echo off
non fallirà mai, quindi l'unico motivo possibile per l'errore sarebbe il reindirizzamento non riuscito. Molto probabilmente fallisce a causa di un problema di blocco, anche se tecnicamente potrebbero esserci altri motivi di fallimento.
È una curiosa "funzionalità" che Windows non imposta la variabile dinamica% ERRORLEVEL% su un errore in caso di errore di reindirizzamento a meno che non venga utilizzato l'operatore ||
. (Vedi File redirection in Windows and %errorlevel%). Pertanto, l'operatore ||
deve leggere il codice di errore restituito a un livello basso, non tramite la variabile% ERRORLEVEL%.
L'utilizzo di queste tecniche per rilevare errori di reindirizzamento può essere molto utile in un contesto batch. Può essere utilizzato per stabilire blocchi che consentono la serializzazione di più eventi in processi paralleli. Ad esempio, può consentire a più processi di scrivere in modo sicuro nello stesso file di registro nello stesso "tempo". How do you have shared log files under Windows?
EDIT
Per quanto riguarda le cartelle bloccate. Non sono sicuro di come Windows implementa questo, forse con un lucchetto. Ma se un processo ha una directory attiva che coinvolge la cartella, la cartella non può essere rinominata. Che può essere facilmente individuati utilizzando
2>nul ren folderName folderName && echo Folder is NOT locked || echo folder is LOCKED
EDIT
Da allora ho imparato che (call)
(con uno spazio) è un comando molto veloce senza effetti collaterali che è garantito per avere successo con il set ERRORLEVEL a 0. E (senza spazio) è un comando rapido senza effetti collaterali che è garantito fallire con ERRORLEVEL 1.
Così ho ora utilizzare la seguente per verificare se un file è bloccato:
2>nul (
>>test.txt (call)
) && (echo file is not locked) || (echo file is locked)
+1 per la pura sintassi cmd (sto ancora cercando di capire come e perché funziona !!!) –
@Adriano - Spiegazione aggiunta :-) – dbenham
Fantastico, mi dispiace non posso andare più di una volta !!! –
Se scaricare e installare gli strumenti del resource kit di Windows Server 2003 esiste un'utility chiamata oh.exe
che elencherà file aperto maniglie per un dato file:
http://www.microsoft.com/en-us/download/details.aspx?id=17657
Una volta installato, riavviare la macchina e sarai in grado di utilizzare l'utilità. È possibile visualizzare tutte le opzioni nel Centro assistenza e supporto, nonché digitando oh /?
nel prompt dei comandi.
(Info da: http://windowsxp.mvps.org/processlock.htm) (? Funziona Windows ha che)
Oltre a great answer dal dbenham, il seguente modulo, infine, aiutarmi a capire la tecnica utilizzata:
(type nul >> file.txt) 2>nul || echo File is locked!
type nul
comando dà un output vuoto e non influenza l'impostazione di eco corrente come il comando echo off
in originale.
Se si desidera utilizzare if–then–else
condizioni ricordate di ordine corretto - dichiarazione successo (&&
) sta prima e la dichiarazione alternativo (||
) sta andando secondo:
command && (echo Command is successful) || (echo Command has failed)
Attenzione con 'if && then || formato else', ricorda che il blocco 'else' verrà eseguito anche se il blocco' then' fallisce. – remram
Per inciso, la soluzione di dbenham sembra anche essere un modo efficace per scoprire se un processo è in esecuzione. E 'stata la soluzione migliore che ho trovato per la seguente applicazione:
start /b "job1.exe >> job1.out"
start /b /wait "job2.exe >> job2.out"
::wait for job1 to finish using dbenham's code to check if job1.out is in use
comparejobs.exe
nota, la scrittura di un messaggio che indica lo stato del file è stato meno utile di un comando batch che impostare un codice di ritorno. Ad esempio, restituire il codice 1 se il file è bloccato.
@echo off
2>nul (
>>test.tmp echo off
) && (EXIT /B 0) || (EXIT /B 1)
Solo che voglio condividere con voi un esempio del mio script sulla base di trucco di @ dbenham
descrizione di questo script: Check_Locked_Files.bat: Questo script può eseguire la scansione e verificare la presenza bloccato file su una serie di cartelle che possono essere modificate nello script; ad esempio, ho scelto il set di cartelle da scansionare:
Set Folders=^
^ "%ProgramData%\Microsoft\Windows\Start Menu\Programs\Startup"^
^ "%UserProfile%\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup"^
^ "%ProgramFiles%\Internet Explorer"^
^ "%ProgramFiles%\Skype"^
^ "%ProgramFiles%\TeamViewer"^
^ "%WinDir%\system32\drivers"^
^ "%Temp%"
Il risultato di output è in formato HTML per una maggiore leggibilità.
Se il file è bloccato, lo mostriamo in rosso altrimenti lo mostriamo in verde.
E l'intero script è: Check_Locked_Files.bat
@echo off
Rem This source is inspired from here
Rem hxxps://stackoverflow.com/questions/
Rem 10518151/how-to-check-in-command-line-if-a-given-file-or-directory-is-locked-used-by-any?answertab=active#tab-top
Rem Thanks for dbenham for this nice trick ;)
Mode con cols=90 lines=5 & color 9E
Title Scan and Check for Locked Files by Hackoo 2017
set "LogFile=%~dp0%~n0.html"
(
echo ^<html^>
echo ^<title^> Scan and Check for locked files by Hackoo 2017^</title^>
echo ^<body bgcolor^=#ffdfb7^>
echo ^<center^>^<b^>Log Started on %Date% @ %Time% by the user : "%username%" on the computer : "%ComputerName%"^</b^>^</center^>
)> "%LogFile%"
echo(
echo --------------------------------------------------------------------------
echo Please Wait a while ....... Scanning for locked files is in progress
echo --------------------------------------------------------------------------
Rem We Play radio just for fun and in order to let the user be patient until the scan ended
Call :Play_DJ_Buzz_Radio
Timeout /T 3 /nobreak>nul
cls
Set Folders=^
^ "%ProgramData%\Microsoft\Windows\Start Menu\Programs\Startup"^
^ "%UserProfile%\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup"^
^ "%ProgramFiles%\Internet Explorer"^
^ "%ProgramFiles%\Skype"^
^ "%ProgramFiles%\TeamViewer"^
^ "%WinDir%\system32\drivers"^
^ "%Temp%"
@For %%a in (%Folders%) Do (
(echo ^<hr^>^<font color^=DarkOrange^>^<B^>Folder : %%a^</B^>^</font^>^<hr^>) >> "%LogFile%"
@for /f "delims=" %%b in ('Dir /A-D /s /b "%%~a\*.*"') do (
Call :Scanning "%%~nxb"
Call:Check_Locked_File "%%~b" "%LogFile%"
)
)
(
echo ^<hr^>
echo ^<center^>^<b^>Log ended on %Date% @ %Time% on the computer : "%ComputerName%"^</b^>^</center^>
echo ^</body^>
echo ^</html^>
)>> "%LogFile%"
Start "" "%LogFile%" & Call :Stop_Radio & exit
::***********************************************************************************
:Check_Locked_File <File> <LogFile>
(
2>nul (
>>%1 (call)
) && (@echo ^<font color^=green^>file "%~1"^</font^>^<br^>
) || (
@echo ^<font color^=red^>file "%~1" is locked and is in use^</font^>^<br^>
)
)>>%2 2>nul
exit /b
::***********************************************************************************
:Scanning <file>
cls
echo(
echo --------------------------------------------------------------------------
echo Please Wait a while... Scanning for %1
echo --------------------------------------------------------------------------
exit /b
::***********************************************************************************
:Play_DJ_Buzz_Radio
Taskkill /IM "wscript.exe" /F >nul 2>&1
Set "vbsfile=%temp%\DJBuzzRadio.vbs"
Set "URL=http://www.chocradios.ch/djbuzzradio_windows.mp3.asx"
Call:Play "%URL%" "%vbsfile%"
Start "" "%vbsfile%"
Exit /b
::**************************************************************
:Play
(
echo Play "%~1"
echo Sub Play(URL^)
echo Dim Sound
echo Set Sound = CreateObject("WMPlayer.OCX"^)
echo Sound.URL = URL
echo Sound.settings.volume = 100
echo Sound.Controls.play
echo do while Sound.currentmedia.duration = 0
echo wscript.sleep 100
echo loop
echo wscript.sleep (int(Sound.currentmedia.duration^)+1^)*1000
echo End Sub
)>%~2
exit /b
::**************************************************************
:Stop_Radio
Taskkill /IM "wscript.exe" /F >nul 2>&1
If Exist "%vbsfile%" Del "%vbsfile%"
::**************************************************************
:: Create the file Running.tmp
ECHO %DATE% > Running.tmp
ECHO %TIME% >> Running.tmp
:: block it and do the work
(
>&2 CALL :Work 30
) >> Running.tmp
:: when the work is finished, delete the file
DEL Running.tmp
GOTO EOF
:: put here the work to be done by the batch file
:Work
ping 127.0.0.1 -n 2 -w 1000 > NUL
ping 127.0.0.1 -n %1 -w 1000 > NUL
:: when the process finishes, the execution go back
:: to the line after the CALL
Ci dispiace ma non è possibile farlo. Dalla riga di comando non c'è modo di sapere se un file è bloccato da un processo (devi provare a fare qualcosa con esso e "catturare" l'errore). –
Penso che PowerShell potrebbe determinare questo. (Sto appena iniziando a leggere Powershell in azione, sono molto impressionato). In Unix, i file bloccati non sono un problema;^/) Buona fortuna a tutti. – shellter
@Adriano - non è vero. Vedere la mia risposta http://stackoverflow.com/a/10520609/1012053 – dbenham