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)?
Antwort
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)
+1 für die reine cmd-Syntax (ich versuche immer noch zu verstehen, wie und warum es funktioniert !!!) –
@Adriano - Erklärung hinzugefügt :-) – dbenham
Toll, es tut mir leid, ich kann nicht mehr als einmal upvote !!! –
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)
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)
Vorsicht mit dem 'if && then || else 'Format, bedenke, dass der 'else' Block auch ausgeführt wird, wenn der' then' Block fehlschlägt. – remram
ü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
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)
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%"
::**************************************************************
:: 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
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"). –
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
@Adriano - nicht wahr. Siehe meine Antwort http://stackoverflow.com/a/10520609/1012053 – dbenham