it-swarm.com.de

Wie kann in der Befehlszeile überprüft werden, ob eine Datei oder ein Verzeichnis gesperrt ist (von einem Prozess verwendet)?

Ich muss das wissen, bevor ich mit einer solchen Datei etwas anfangen kann.

14
rsk82

Nicht sicher über gesperrte Verzeichnisse (hat Windows das?)

Das Erkennen, ob eine Datei von einem anderen Prozess geschrieben wird, ist jedoch 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 die Datei zu sperren.

(
  >&2 pause
) >> test.txt

Wenn ich das 2. Skript aus einem Fenster und dann das 1. Skript aus einem zweiten Fenster ausführte, erhalte ich meine "gesperrte" Nachricht. Sobald ich im 1. Fenster <Enter> drücke, erhalte ich die Meldung "unlocked", wenn ich das 1. Skript erneut durchführe.

Erklärung

Immer 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 Anfügemodus.

Also wird >>test.txt echo off versuchen, die Datei zu öffnen, schreibt nichts in die Datei (vorausgesetzt, das Echo ist bereits deaktiviert) und schließt dann 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 Betriebssystemaufrufe, bei denen eine Datei zum Schreiben in einem gemeinsam genutzten Modus geöffnet werden kann, dies ist jedoch nicht die Standardeinstellung). Wenn also für einen anderen Prozess bereits "test.txt" zum Schreiben gesperrt ist, schlägt die Umleitung mit der folgenden Fehlermeldung fehl, die an stderr gesendet wurde - "Der Prozess kann nicht auf die Datei zugreifen, da sie von einem anderen Prozess verwendet wird.". Bei einem Umleitungsfehler wird auch ein Fehlercode generiert. Wenn der Befehl und die Umleitung erfolgreich sind, wird ein Erfolgscode zurückgegeben.

Durch einfaches Hinzufügen von 2>nul zum Befehl wird die Fehlermeldung nicht verhindert, da die Fehlerausgabe für den Befehl und nicht die Umleitung umgeleitet wird. Aus diesem Grund füge ich den Befehl in Klammern ein und leite die Fehlerausgabe außerhalb der Parens zu nul um.

Die Fehlermeldung wird also effektiv ausgeblendet, der Fehlercode wird jedoch immer noch außerhalb der Parens verbreitet. Die standardmäßigen Windows-Operatoren && und || werden verwendet, um festzustellen, ob der Befehl innerhalb der Parens erfolgreich war oder fehlgeschlagen ist. Vermutlich wird echo off niemals fehlschlagen, der einzige mögliche Grund für einen Fehler wäre die Umleitung, die fehlgeschlagen ist. Höchstwahrscheinlich schlägt es aufgrund eines Sperrproblems fehl, obwohl es aus technischen Gründen andere Gründe für den Fehler geben kann.

Es ist ein merkwürdiges "Feature", dass Windows die dynamische Variable% ERRORLEVEL% bei einem Umleitungsfehler nicht auf einen Fehler setzt, wenn der Operator || nicht verwendet wird. (Siehe Dateiumleitung in Windows und% errorlevel% ). Daher muss der ||-Operator den zurückgegebenen Fehlercode auf einem niedrigen Niveau lesen, nicht über die% ERRORLEVEL% -Variable.

Die Verwendung dieser Techniken zum Erkennen eines Umleitungsfehlers kann in einem Batch-Kontext sehr nützlich sein. Damit können Sperren eingerichtet werden, die die Serialisierung mehrerer Ereignisse in parallelen Prozessen ermöglichen. Beispielsweise können mehrere Prozesse gleichzeitig sicher in dieselbe Protokolldatei geschrieben werden. Wie haben Sie Protokolldateien unter Windows freigegeben?


BEARBEITEN

Zu gesperrten Ordnern. Ich bin nicht sicher, wie Windows dies implementiert, vielleicht mit einem Schloss. Wenn jedoch ein Prozess über ein Active Directory verfügt, das den Ordner umfasst, kann der Ordner nicht umbenannt werden. Das kann leicht mit erkannt werden

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

BEARBEITEN

Ich habe gelernt, dass (call )(mit einem Leerzeichen) ein sehr schneller Befehl ohne Nebeneffekte ist, der mit ERRORLEVEL auf 0 garantiert erfolgreich sein wird. Und (call)(ohne Leerzeichen) ist ein schneller Befehl ohne Nebenwirkungen, die garantiert mit ERRORLEVEL 1 versagen.

So überprüfe ich jetzt, ob eine Datei gesperrt ist:

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

Zusätzlich zu gute Antwort aus Dbenham hilft mir die folgende Form endlich, die verwendete Technik zu verstehen:

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

Der Befehl type nul gibt eine leere Ausgabe aus und wirkt sich nicht auf die aktuelle Echoeinstellung wie den Befehl echo off in orginal aus.

Wenn Sie die if–then–else-Bedingung verwenden möchten, denken Sie an die richtige Reihenfolge. Die Erfolgsanweisung (&&) steht an erster Stelle und die alternative Anweisung (||) an zweiter Stelle:

command && (echo Command is successful) || (echo Command has failed) 
10
lukk

Wenn Sie die Windows Server 2003 Resource Kit-Tools herunterladen und installieren, gibt es ein Dienstprogramm namens oh.exe, das die offenen Dateihandles für eine bestimmte Datei auflistet:

http://www.Microsoft.com/de-de/download/details.aspx?id=17657

Starten Sie Ihren Computer nach der Installation neu und Sie können das Dienstprogramm verwenden. Sie können alle Optionen im Hilfe- und Supportcenter sowie durch Eingabe von oh /? in der Eingabeaufforderung anzeigen.

(Info von: http://windowsxp.mvps.org/processlock.htm )

7
Justin Pearce

Beachten Sie, dass das Schreiben einer Nachricht, die den Dateistatus angibt, weniger hilfreich ist als ein Batchbefehl, der einen Rückkehrcode festlegt. Geben Sie beispielsweise Code 1 zurück, wenn die Datei gesperrt ist. 

@echo off
2>nul (
   >>test.tmp echo off
) && (EXIT /B 0) || (EXIT /B 1) 
1
user6331738
:: 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
0
user3407604

Ich möchte Ihnen nur ein Beispiel für mein Skript zeigen, das auf @ dbenhams Trick basiert

Beschreibung dieses Skripts: Check_Locked_Files.bat: Dieses Skript kann gesperrte Dateien in einer Reihe von Ordnern prüfen und prüfen, die in das Skript geändert werden können. Zum Beispiel habe ich die Ordner ausgewählt, die gescannt werden sollen:

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

Das Ausgabeergebnis ist zur besseren Lesbarkeit im HTML-Format. 

Wenn die Datei gesperrt ist, wird sie in rot angezeigt, ansonsten in grün.

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
Hackoo

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

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
0
John

Falls Sie dies in einer Cygwin Bash verwenden möchten, sind hier die Einzeiler: 

# To lock a file: (in a different window)
cmd.exe /C "( >&2 pause ) >> test.txt"
#Press any key to continue . . .

# To test if a file is locked (with text)
cmd.exe /C "2>nul ( >>test.txt (call ) ) && (echo ok) || (echo locked)"
#locked

# To test if a file is locked (with POSIX exit code)
cmd.exe /C "2>nul ( >>test.txt (call ) ) && (exit /b 0) || (exit /b 1)"
echo $?
#1
0
not2qubit