2012-05-09 16 views
14

Necesito saberlo antes de cualquier intento de hacer algo con dicho archivo.¿Cómo verificar en línea de comandos si un archivo o directorio determinado está bloqueado (utilizado por cualquier proceso)?

+1

Lo sentimos, pero no puede hacerlo. Desde la línea de comandos no hay forma de saber si un archivo está bloqueado por un proceso (hay que intentar hacer algo con él y "atrapar" el error). –

+0

Creo que PowerShell podría determinar esto. (Estoy empezando a leer Powershell en acción, estoy muy impresionado). En Unix, los archivos bloqueados no son un problema;^/) Buena suerte para todos. – shellter

+3

@Adriano - no es cierto. Ver mi respuesta http://stackoverflow.com/a/10520609/1012053 – dbenham

Respuesta

55

No está seguro acerca de los directorios bloqueados

Pero detectar si un archivo se escribe en otro proceso no es difícil.

@echo off 
2>nul (
    >>test.txt echo off 
) && (echo file is not locked) || (echo file is locked) 

Utilizo la siguiente secuencia de comandos de prueba desde otra ventana para colocar un bloqueo en el archivo.

(
    >&2 pause 
) >> test.txt 

Cuando ejecuto el segundo guión de una ventana y vuelva a ejecutar la primera secuencia de comandos desde una ventana del segundo, me sale mi mensaje "bloqueado". Una vez que presiono <Enter> en la primera ventana, aparece el mensaje "desbloqueado" si vuelvo a ejecutar el primer guión.

Explicación

Siempre que la salida de un comando se redirige a un archivo, el archivo, por supuesto, se debe abrir para acceso de escritura. La sesión de Windows CMD intentará abrir el archivo, incluso si el comando no produce ningún resultado.

El operador de redirección >> abre el archivo en modo de adición.

Así que >>test.txt echo off intentará abrir el archivo, no escribe nada en el archivo (asumiendo que el eco ya está desactivado), y luego cierra el archivo. El archivo no se modifica de ninguna manera.

La mayoría de los procesos bloquea un archivo cada vez que abren un archivo para acceso de escritura. (Hay llamadas al sistema operativo que permiten abrir un archivo para escribir en un modo compartido, pero ese no es el predeterminado). Entonces, si otro proceso ya tiene bloqueado "test.txt" para la escritura, la redirección fallará y se enviará el siguiente mensaje de error a stderr: "El proceso no puede acceder al archivo porque lo está utilizando otro proceso".. También se generará un código de error cuando falla la redirección. Si el comando y la redirección tienen éxito, se devuelve un código de éxito.

Simplemente agregue 2>nul al comando no evitará el mensaje de error porque redirige la salida de error para el comando, no la redirección. Es por eso que encierro el comando entre paréntesis y luego redirijo la salida de error a nul fuera de los parens.

De modo que el mensaje de error está efectivamente oculto, pero el código de error aún se propaga fuera de los parens. Los operadores estándar de Windows && y || se utilizan para detectar si el comando dentro de los parens fue exitoso o no.Es de suponer que echo off nunca fallará, por lo que la única razón posible de falla sería la redirección fallida. Lo más probable es que falle debido a un problema de bloqueo, aunque técnicamente podría haber otras razones para el fracaso.

Es una "característica" curiosa que Windows no establece la variable dinámica% ERRORLEVEL% en un error al fallar la redirección a menos que se utilice el operador ||. (Ver File redirection in Windows and %errorlevel%). Por lo tanto, el operador || debe leer el código de error devuelto en un nivel bajo, no a través de la variable% ERRORLEVEL%.

Usar estas técnicas para detectar fallas de redirección puede ser muy útil en un contexto por lotes. Se puede usar para establecer bloqueos que permiten la serialización de eventos múltiples en procesos paralelos. Por ejemplo, puede permitir que múltiples procesos escriban de manera segura en el mismo archivo de registro en el "mismo" momento. How do you have shared log files under Windows?


EDITAR

En cuanto carpetas bloqueadas. No estoy seguro de cómo Windows implementa esto, quizás con un bloqueo. Pero si un proceso tiene un directorio activo que involucra la carpeta, entonces la carpeta no puede renombrarse. Que puede ser fácilmente detectado usando

2>nul ren folderName folderName && echo Folder is NOT locked || echo folder is LOCKED 

EDITAR

desde entonces he aprendido que (call)(con un espacio) es un comando muy rápido y sin efectos secundarios que está garantizado para tener éxito con el conjunto ERRORLEVEL a 0. Y (call)(sin espacio) es un comando rápido sin efectos secundarios que se garantiza que falla con ERRORLEVEL 1.

Así que ahora la siguiente manera para comprobar si un archivo está bloqueado:

2>nul (
    >>test.txt (call) 
) && (echo file is not locked) || (echo file is locked) 
+0

+1 para la sintaxis de cmd puro (¡Todavía estoy tratando de entender cómo y por qué funciona!) –

+2

@Adriano - Explicación agregada :-) – dbenham

+2

¡Genial, lo siento, no puedo votar más de una vez! –

7

Si descarga e instala el Windows Server 2003 Resource Kit Tools hay una utilidad llamada oh.exe que enumerará de archivo abierto para un determinado archivo:

http://www.microsoft.com/en-us/download/details.aspx?id=17657

Una vez instalado, reinicie su máquina y podrás usar la utilidad. Puede ver todas las opciones en el Centro de ayuda y soporte técnico y escribir oh /? en el símbolo del sistema.

(Información de: http://windowsxp.mvps.org/processlock.htm) (? Qué Windows tiene que)

9

Además de great answer de dbenham, el siguiente formulario finalmente me ayudan a entender la técnica utilizada:

comando
(type nul >> file.txt) 2>nul || echo File is locked! 

type nul da una salida vacía y no afecta la configuración de eco actual como echo off comando en original.

Si desea utilizar if–then–else condición de recordar el orden correcto - Declaración de éxito (&&) va primero y declaración alternativa (||) va en segundo lugar:

command && (echo Command is successful) || (echo Command has failed) 
+2

Ten cuidado con el 'if && then || el formato de else, recuerda que el bloque 'else' también se ejecutará si falla el bloque' then'. – remram

0

Por cierto, la solución de dbenham También parece haber una forma efectiva de averiguar si un proceso se está ejecutando. Fue la mejor solución que encontré para la siguiente aplicación:

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 
1

Nota, la escritura de un mensaje que indica el estado del archivo era menos útil que un comando por lotes que establece un código de retorno. Por ejemplo, devuelve el código 1 si el archivo está bloqueado.

@echo off 
2>nul (
    >>test.tmp echo off 
) && (EXIT /B 0) || (EXIT /B 1) 
1

Sólo quiero compartir con ustedes un ejemplo de mi guión basado en truco de @ dbenham

descripción del script: Check_Locked_Files.bat: Este script puede escanear y comprobar si hay bloqueada archivos en un conjunto de carpetas que se pueden modificar en el script; por ejemplo, he elegido ese conjunto de carpetas para escanear:

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%" 

El resultado de salida está en formato HTML para una mayor legibilidad.

Si el archivo está bloqueado, lo mostramos en color rojo, de lo contrario, lo mostramos en color verde.

Y toda la secuencia de comandos es: 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%" 
::************************************************************** 
0
:: 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 
Cuestiones relacionadas