2012-05-09 16 views
14

Ich muss das vor jedem Versuch wissen, etwas mit einer solchen Datei zu tun.Wie überprüfe ich die Befehlszeile, wenn eine Datei oder ein Verzeichnis gesperrt ist (wird von einem beliebigen Prozess verwendet)?

+1

Sorry, aber Sie können es nicht tun. Über die Befehlszeile gibt es keine Möglichkeit zu wissen, ob eine Datei von einem Prozess gesperrt ist (Sie müssen versuchen, etwas damit zu tun und den Fehler zu "fangen"). –

+0

Ich würde denken, Powershell könnte dies feststellen. (Ich habe Powershell gerade in Aktion gelesen, ich bin sehr beeindruckt). In Unix sind gesperrte Dateien kein Problem;^/) Viel Glück für alle. – shellter

+3

@Adriano - nicht wahr. Siehe meine Antwort http://stackoverflow.com/a/10520609/1012053 – dbenham

Antwort

55

nicht über gesperrt Verzeichnisse sicher

aber erkennen, ob eine Datei von einem anderen Prozess geschrieben wird, ist nicht schwierig.

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

Ich verwende das folgende Testskript aus einem anderen Fenster, um eine Sperre auf die Datei zu setzen.

(
    >&2 pause 
) >> test.txt 

Als ich das zweite Skript von einem Fenster laufen und dann das erste Skript aus einem zweiten Fenster laufen, bekomme ich meine „gesperrt“ -Meldung. Sobald ich im ersten Fenster <Enter> drücke, erhalte ich die Meldung "unlocked", wenn ich das 1. Skript erneut durchführe.

Erklärung

Jedes Mal, wenn die Ausgabe eines Befehls in eine Datei umgeleitet wird, muss die Datei natürlich für den Schreibzugriff geöffnet werden. Die Windows CMD-Sitzung versucht, die Datei zu öffnen, auch wenn der Befehl keine Ausgabe erzeugt. Der >> Umleitungsoperator öffnet die Datei im Append-Modus.

So >>test.txt echo off wird versuchen, die Datei zu öffnen, es schreibt nichts in die Datei (vorausgesetzt, Echo ist bereits deaktiviert), und dann schließt es die Datei. Die Datei wird in keiner Weise geändert.

Die meisten Prozesse sperren eine Datei, wenn sie eine Datei für den Schreibzugriff öffnen. (Es gibt OS-Systemaufrufe, die das Öffnen einer Datei zum Schreiben in einem freigegebenen Modus ermöglichen, dies ist jedoch nicht der Standard). Wenn also ein anderer Prozess "test.txt" bereits zum Schreiben gesperrt hat, schlägt die Umleitung mit folgender Fehlermeldung fehl, die an stderr gesendet wurde: "Der Prozess kann nicht auf die Datei zugreifen, weil sie von einem anderen Prozess verwendet wird.". Bei einem Umleitungsfehler wird ebenfalls ein Fehlercode generiert. Wenn der Befehl und die Umleitung erfolgreich sind, wird ein Erfolgscode zurückgegeben.

Das einfache Hinzufügen 2>nul zum Befehl wird die Fehlermeldung nicht verhindern, da es die Fehlerausgabe für den Befehl umleitet, nicht die Umleitung. Deshalb lege ich den Befehl in Klammern an und leite die Fehlerausgabe dann auf nul außerhalb des Parens um.

So ist die Fehlermeldung effektiv ausgeblendet, aber der Fehlercode wird immer noch außerhalb der Parens propagiert. Die Standardoperatoren Windows && und || werden verwendet, um festzustellen, ob der Befehl innerhalb des Parens erfolgreich war oder fehlgeschlagen ist.Vermutlich echo off wird nie fehlschlagen, so der einzige mögliche Grund für einen Fehler wäre die Umleitung fehlgeschlagen. Höchstwahrscheinlich scheitert es aufgrund eines Sperrproblems, obwohl es technisch andere Gründe für einen Fehler geben könnte.

Es ist ein seltsames "Feature", dass Windows die dynamische Variable% ERRORLEVEL% nicht auf einen Fehler bei Umleitungsfehler setzt, wenn der Operator || nicht verwendet wird. (Siehe). Daher muss der Operator || den zurückgegebenen Fehlercode auf einer niedrigen Stufe lesen, nicht über die Variable% ERRORLEVEL%.

Die Verwendung dieser Techniken zur Erkennung von Umleitungsfehlern kann im Stapelkontext sehr nützlich sein. Es kann verwendet werden, um Sperren einzurichten, die die Serialisierung mehrerer Ereignisse in parallelen Prozessen ermöglichen. Zum Beispiel kann es mehreren Prozessen ermöglichen, zur selben Zeit sicher in dieselbe Protokolldatei zu schreiben. How do you have shared log files under Windows?


EDIT

gesperrten Ordner Bezug. Ich bin mir nicht sicher, wie Windows dies implementiert, vielleicht mit einer Sperre. Wenn ein Prozess jedoch ein aktives Verzeichnis mit dem Ordner enthält, kann der Ordner nicht umbenannt werden. Das kann leicht

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

EDIT nachzuweisenden

ich da gelernt, dass (call)(mit Leerzeichen) ist ein sehr schnelles, ohne Nebenwirkungen, die garantiert mit Error-Set zum Erfolg zu 0. Und (call)(ohne Leerzeichen) ist ein schneller Befehl ohne Nebenwirkungen, der mit ERRORLEVEL 1 garantiert fehlschlägt.

So verwende ich nun folgendes zu überprüfen, ob eine Datei gesperrt ist:

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

+1 für die reine cmd-Syntax (ich versuche immer noch zu verstehen, wie und warum es funktioniert !!!) –

+2

@Adriano - Erklärung hinzugefügt :-) – dbenham

+2

Toll, es tut mir leid, ich kann nicht mehr als einmal upvote !!! –

7

Wenn Sie die Windows Server 2003 Resource Kit Tools dort herunterzuladen und zu installieren ist ein Dienstprogramm oh.exe genannt, die geöffnete Datei für eine bestimmte Datei-Handles auflistet:

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

Wenn Sie es installiert, Ihren Rechner neu starten und Sie können das Dienstprogramm verwenden. Sie können alle Optionen im Hilfe- und Supportcenter sowie in der Eingabeaufforderung oh /? eingeben.

(Info aus: http://windowsxp.mvps.org/processlock.htm) (? Wird Windows hat, dass)

9

Neben great answer von dbenham schließlich das folgende Formular mir verwendete Technik verstehen helfen:

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

type nul Befehl gibt leere Ausgabe und hat keinen Einfluss auf die aktuelle Echo-Einstellung wie echo off Befehl in Orginal.

Wenn Sie if–then–else Zustand verwenden, der richtigen Reihenfolge erinnern - Erfolgsrechnung (&&) wird erste und alternative Erklärung (||) wird Sekunde:

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

Vorsicht mit dem 'if && then || else 'Format, bedenke, dass der 'else' Block auch ausgeführt wird, wenn der' then' Block fehlschlägt. – remram

0

übrigens dbenham Lösung auch zu sein scheint effektiver Weg, um herauszufinden, ob ein Prozess läuft. Es war die beste Lösung, die ich für die folgende Anwendung gefunden:

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

Hinweis, das Schreiben einer Meldung des Status der Datei war weniger nützlich als ein Batch-Befehl, der einen Return-Code festgelegt. Geben Sie beispielsweise den Code 1 zurück, wenn die Datei gesperrt ist.

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

Nur möchte ich mit Ihnen ein Beispiel für mein Skript basiert teilen auf @ dbenham Trick

Beschreibung dieses Skripts: Check_Locked_Files.bat: Dieses Skript kann für gesperrte scannen und überprüfen Dateien in einer Reihe von Ordnern, die in das Skript geändert werden können; zum Beispiel habe ich jene Gruppe von Ordnern gewählt sucht werden soll:

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

Der Ausgang ist im HTML-Format für mehr Lesbarkeit.

Wenn die Datei gesperrt ist, zeigen wir sie in roter Farbe, ansonsten zeigen wir sie in grüner Farbe.

Und das ganze Skript ist: 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