Мне нужно знать, что перед любой попыткой сделать что-либо с таким файлом.Как проверить в командной строке, если данный файл или каталог заблокирован (используется любым процессом)?
ответ
Не уверен, что заблокированные каталогов
Но обнаружения, если файл записывается в другой процесс не сложно.
@echo off
2>nul (
>>test.txt echo off
) && (echo file is not locked) || (echo file is locked)
Я использую следующий тестовый сценарий из другого окна, чтобы поместить замок в файл.
(
>&2 pause
) >> test.txt
Когда я запускаю 2-й сценарий из одного окна, а затем запустить 1-й сценарий из окна второго, я получаю мое «запертое» сообщение. Как только я нажимаю <Enter>
в 1-ом окне, я получаю сообщение «разблокирован», если я перезапущу 1-й скрипт.
Объяснение
Всякий раз, когда выход из команды перенаправляется в файл, файл, конечно, должен быть открыт для записи. Сценарий Windows CMD попытается открыть файл, даже если команда не производит никакого вывода.
Оператор перенаправления >>
открывает файл в режиме добавления.
Таким образом, >>test.txt echo off
попытается открыть файл, он ничего не записывает в файл (предполагается, что эхо уже выключено), а затем оно закрывает файл. Файл не изменяется каким-либо образом.
Большинство процессов блокирует файл, когда они открывают файл для доступа к записи. (Существуют системные вызовы ОС, которые позволяют открывать файл для записи в режиме общего доступа, но это не значение по умолчанию). Таким образом, если в другом процессе уже есть «test.txt», который заблокирован для записи, то перенаправление не будет выполнено со следующим сообщением об ошибке, отправленным в stderr - «Процесс не может получить доступ к файлу, потому что он используется другим процессом».. Также при сбое перенаправления генерируется код ошибки. Если команда и перенаправление успешны, возвращается код успеха.
Просто добавление 2>nul
к команде не предотвратит сообщение об ошибке, поскольку оно перенаправляет вывод ошибки для команды, а не перенаправление. Вот почему я заключу команду в круглые скобки и затем перенаправляю вывод ошибки в nul за пределами parens.
Таким образом, сообщение об ошибке эффективно скрыто, но код ошибки по-прежнему распространяется за пределами parens. Стандартные операторы Windows &&
и ||
используются для определения того, была ли команда внутри паренов успешной или неудачной.Предположительно, echo off
никогда не потерпит неудачу, поэтому единственной возможной причиной отказа будет перенаправление. Скорее всего, это не удается из-за проблемы с блокировкой, хотя технически могут быть другие причины отказа.
Любопытная «функция», при которой Windows не устанавливает динамическую переменную% ERRORLEVEL% при ошибке при перенаправлении, если не используется оператор ||
. (См. File redirection in Windows and %errorlevel%). Поэтому оператор ||
должен прочитать возвращаемый код ошибки на некотором низком уровне, а не через переменную% ERRORLEVEL%.
Использование этих методов для обнаружения отказа перенаправления может быть очень полезным в пакетном контексте. Его можно использовать для установки блокировок, которые позволяют сериализовать несколько событий в параллельных процессах. Например, он может позволить нескольким процессам безопасно записывать в один и тот же файл журнала в «то же самое время». How do you have shared log files under Windows?
EDIT
Что касается Защищенные папки. Я не уверен, как Windows это реализует, возможно, с блокировкой. Но если в процессе есть активный каталог с участием папки, папка не может быть переименована. Это можно легко обнаружить с помощью
2>nul ren folderName folderName && echo Folder is NOT locked || echo folder is LOCKED
EDIT
С тех пор я узнал, что (call)
(с пробелом) очень быстро команда без побочных эффектов, которые гарантированно добиться успеха с множеством ERRORLEVEL до 0. И (call)
(без пробела) - это быстрая команда без побочных эффектов, которая гарантированно завершится неудачей с ERRORLEVEL 1.
Так что я теперь использовать следующую команду для проверки, если файл заблокирован:
2>nul (
>>test.txt (call)
) && (echo file is not locked) || (echo file is locked)
+1 для чистого синтаксиса cmd (я все еще пытаюсь понять, как и почему он работает !!!) –
@Adriano - Explanation added :-) – dbenham
Отлично, мне жаль, что я не могу повышать свою репутацию более одного раза !!! –
Если вы загрузите и установите Windows Server 2003 Resource Kit Tools есть утилита под названием oh.exe
, который будет список дескрипторов открытых файлов для данного файла:
http://www.microsoft.com/en-us/download/details.aspx?id=17657
После того, как вы установите его, перезагрузить вашу машину и вы сможете использовать эту утилиту. Вы можете просмотреть все параметры в Центре справки и поддержки, а также ввести oh /?
в командной строке.
(Информация от: http://windowsxp.mvps.org/processlock.htm) (? Это Windows, есть что)
В дополнение к great answer из dbenham, следующая форма, наконец, помочь мне понять используемую технику:
(type nul >> file.txt) 2>nul || echo File is locked!
type nul
команда дает оценку пустой выход и не влияет на текущее значение эха, например echo off
команда в оригинале.
Если вы хотите использовать if–then–else
состояние помнить о правильном порядке - успех заявление (&&
) собирается первым и альтернативного оператора (||
) будет второй:
command && (echo Command is successful) || (echo Command has failed)
Остерегайтесь 'if && then || помните, что блок 'else' также будет выполнен, если блок' then' завершится с ошибкой. – remram
Кстати, решение dbenham также, как представляется, эффективный способ выяснить, работает ли процесс. Это было лучшее решение, которое я нашел для следующего применения:
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, если файл заблокирован.
@echo off
2>nul (
>>test.tmp echo off
) && (EXIT /B 0) || (EXIT /B 1)
Просто я хочу поделиться с вами пример моего сценария на основе трюк @ dbenham в
Описание этого сценария: Check_Locked_Files.bat: Этот сценарий может сканировать и проверить заблокирован файлы в наборе папок, которые могут быть изменены в скрипт; например, я выбрал тот набор папок, которые нужно отсканировать:
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%"
Результат вывода в формате HTML для большей удобочитаемости.
Если файл заблокирован, мы показываем его красным цветом, иначе мы показываем его зеленым цветом.
И весь сценарий: 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
Извините, но вы не можете это сделать. Из командной строки не существует способа узнать, заблокирован ли файл процессом (вам нужно попытаться что-то с этим сделать и «поймать» ошибку). –
Я бы подумал, что powershell может это определить. (Просто начинаю читать Powershell в действии, я очень впечатлен). В unix заблокированные файлы не являются проблемой;^/) Удачи всем. – shellter
@Adriano - не верно. См. Мой ответ http://stackoverflow.com/a/10520609/1012053 – dbenham