2012-05-09 30 views
14

Muszę to wiedzieć przed każdą próbą zrobienia czegokolwiek z takim plikiem.Jak sprawdzić w linii poleceń, czy dany plik lub katalog jest zablokowany (używany przez dowolny proces)?

+1

Niestety, ale nie można tego zrobić. Z linii poleceń nie można ustalić, czy plik jest zablokowany przez proces (trzeba spróbować coś z nim zrobić i "złapać" błąd). –

+0

Myślę, że Power Shell mógłby to ustalić. (Właśnie zaczynam czytać Powershell w akcji, jestem pod wrażeniem). W systemie Unix zablokowane pliki nie stanowią problemu;^/) Powodzenia dla wszystkich. – shellter

+3

@Adriano - nieprawda. Zobacz moją odpowiedź http://stackoverflow.com/a/10520609/1012053 – dbenham

Odpowiedz

55

Nie wiesz o zablokowanych katalogów

Ale wykrycie, czy plik jest zapisywany przez inny proces nie jest trudny.

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

Używam następującego skryptu testowego z innego okna do umieszczenia blokady na pliku.

Po uruchomieniu drugiego skryptu z jednego okna, a następnie uruchomieniu pierwszego skryptu z drugiego okna, otrzymuję komunikat "zablokowany". Po naciśnięciu klawisza <Enter> w 1. oknie otrzymuję komunikat "odblokowany", jeśli ponownie uruchomię pierwszy skrypt.

Wyjaśnienie

Gdy wyjście polecenia jest przekierowywany do pliku, plik oczywiście musi być otwarty dla dostępu zapisu. Sesja Windows CMD podejmie próbę otwarcia pliku, nawet jeśli polecenie nie generuje żadnych danych wyjściowych.

Operator przekierowania >> otwiera plik w trybie dołączania.

Tak więc spróbuje otworzyć plik, nie zapisuje niczego w pliku (zakładając, że echo jest już wyłączone), a następnie zamyka plik. Plik nie jest w żaden sposób modyfikowany.

Większość procesów blokuje plik za każdym razem, gdy otwiera plik do zapisu. (Istnieją wywołania systemowe systemu operacyjnego, które umożliwiają otwarcie pliku do zapisu w trybie współdzielonym, ale nie jest to ustawienie domyślne). Jeśli więc inny proces ma już "test.txt" zablokowany do zapisu, przekierowanie zakończy się niepowodzeniem z następującym komunikatem o błędzie wysłanym do stderr - "Proces nie może uzyskać dostępu do pliku, ponieważ jest używany przez inny proces.". Również kod błędu zostanie wygenerowany po awarii przekierowania. Jeśli polecenie i przekierowanie się powiedzie, zwracany jest kod sukcesu.

Po prostu dodanie do polecenia 2>nul nie zapobiega wyświetleniu komunikatu o błędzie, ponieważ przekierowuje wyjście błędu dla polecenia, a nie przekierowanie. Dlatego załączam polecenie w nawiasach, a następnie przekierowuję wyjście błędów do nul poza parens.

Tak więc komunikat o błędzie jest skutecznie ukryty, ale kod błędu jest nadal propagowany poza parens. Standardowe operatory Windows && i || służą do wykrywania powodzenia lub niepowodzenia polecenia wewnątrz parens.Prawdopodobnie echo off nigdy nie zawiedzie, więc jedyną możliwą przyczyną niepowodzenia byłoby przekierowanie. Najprawdopodobniej zawiedzie z powodu problemu z blokowaniem, choć technicznie mogą istnieć inne powody niepowodzenia.

Jest to ciekawa "funkcja", której system Windows nie ustawił zmiennej dynamicznej% ERRORLEVEL% na błąd po awarii przekierowania, chyba że użyto operatora ||. (Patrz File redirection in Windows and %errorlevel%). Zatem operator || musi odczytać zwrócony kod błędu na pewnym niskim poziomie, a nie za pomocą zmiennej% ERRORLEVEL%.

Korzystanie z tych technik w celu wykrycia awarii przekierowania może być bardzo przydatna w kontekście partii. Można go użyć do ustanowienia blokad, które umożliwiają szeregowanie wielu zdarzeń w procesach równoległych. Na przykład może umożliwić wielu procesom bezpieczne zapisywanie do tego samego pliku dziennika w tym samym czasie. How do you have shared log files under Windows?


EDIT

chodzi foldery zablokowane. Nie jestem pewien, w jaki sposób system Windows to implementuje, być może z blokadą. Ale jeśli proces ma aktywny katalog zawierający folder, nie można zmienić nazwy folderu. Które można łatwo wykryć za pomocą

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

EDIT

Mam ponieważ dowiedział się, że (call)(ze spacją) jest bardzo szybka komenda bez skutków ubocznych, które są gwarantowane, aby odnieść sukces z zestawem ERRORLEVEL do 0. I (call)(bez spacji) jest szybką komendą bez efektów ubocznych, które z pewnością ulegną awarii z ERRORLEVEL 1.

Więc teraz używać następujących czynności, aby sprawdzić, czy plik jest zablokowany

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

+1 dla czystej składni cmd (wciąż próbuję zrozumieć, jak i dlaczego działa!) –

+2

@Adriano - Wyjaśnienie dodano :-) – dbenham

+2

Świetnie, przykro mi, nie mogę głosować więcej niż raz !!! –

7

Jeśli pobranie i zainstalowanie zestawu narzędzi zasobów systemu Windows Server 2003 jest narzędzie o nazwie oh.exe że pokaże otwarty plik uchwyty do danego pliku:

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

Po zainstalowaniu go, uruchom ponownie komputer i będziesz mógł korzystać z narzędzia. Możesz zobaczyć wszystkie opcje w Centrum pomocy i obsługi technicznej, a także wpisując oh /? w wierszu polecenia.

(Info z: http://windowsxp.mvps.org/processlock.htm) (? Nie ma, że ​​w systemie Windows)

9

Oprócz great answer od dbenham następującą postać wreszcie mi pomóc zrozumieć stosowaną techniką:

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

type nul komenda daje puste wyjście i nie wpływa na bieżące ustawienie echa, takie jak echo off w oryginalnym.

Jeśli chcesz użyć if–then–else warunek pamiętać o właściwej kolejności - sukces Statement (&&) idzie pierwszy i alternatywnej rachunku (||) będzie drugi:

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

Uwaga na 'if && then || w przeciwnym razie pamiętaj, że blok 'else' zostanie również wykonany, jeśli blok' then' się nie powiedzie. – remram

0

Nawiasem mówiąc, rozwiązanie dbenham wydaje się być również skuteczny sposób sprawdzenia, czy proces jest uruchomiony. To było najlepsze rozwiązanie znalazłem dla następujących aplikacji:

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

Uwaga, pisanie wiadomości stwierdzającego status plik był mniej przydatne niż polecenia wsadowego ustawić kod zwrotny. Na przykład kod powrotu 1, jeśli plik jest zablokowany.

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

Tylko chcę się z wami podzielić przykład mojego skryptu opiera się na podstęp @ dbenham za

opis tego skryptu: Check_Locked_Files.bat: Ten skrypt może skanować i sprawdzić zablokowane pliki na zestawie folderów, które można modyfikować w skrypcie; na przykład wybrałem zestaw folderów do skanowania:

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

Wynik wyjściowy jest w formacie HTML dla większej czytelności.

Jeśli plik jest zablokowany, wyświetlamy go w kolorze czerwonym, w przeciwnym razie wyświetlamy go w kolorze zielonym.

I cały skrypt jest: 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 
Powiązane problemy