Advertisement
GCRaistlin

dirsize.cmd

Dec 20th, 2013
118
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 11.84 KB | None | 0 0
  1. @echo off
  2. echo/
  3. echo dirsize v1.0.12
  4. echo (c) 2017 GCRaistlin. Licensed under GNU GPL v3.
  5. echo/
  6. setlocal disabledelayedexpansion
  7. if defined IgnoreError set IgnoreError=
  8.  
  9. rem Если флаг установлен, скрипт игнорирует ошибки обработки каталогов
  10. rem set IgnoreError=1
  11. rem Разделитель имени каталога и размера в выводе. Если результат
  12. rem предполагается парсить, то рекомендуется использовать один из символов:
  13. rem "<|>". По умолчанию - пробел.
  14. rem set "Separator=|"
  15.  
  16. set Root=%1
  17.  
  18.  
  19. rem Don't delete 2 empty lines above, or else the script will fail if
  20. rem the argument is ended with "^".
  21.  
  22. 2>nul (for /f "tokens=1 delims==" %%A in ('set Error') do set "%%A=")
  23. set Error2=Invalid root directory
  24. set Error4=Size too big
  25.  
  26. if not defined Root goto _Help
  27. call :_IsDir %Root%
  28. if errorlevel 1 (set errorlevel=2& goto _Exit)
  29.  
  30. rem Уровни текущего (обрабатываемого) и предыдущего (обработанного) каталога
  31. rem (количество "\" в полном имени каталога)
  32. if defined Lvl set Lvl=
  33. rem PrevLvl устанавливаем в невозможное значение, т. к. пустое не годится -
  34. rem см. (*)
  35. set PrevLvl=0
  36. rem Уровень %Root%
  37. if defined Lvl0 set Lvl0=
  38. rem См. ниже
  39. 2>nul (for /f "tokens=1 delims==" %%A in ('set Name') do set "%%A=")
  40. 2>nul (for /f "tokens=1 delims==" %%A in ('set SizeB') do set "%%A=")
  41. 2>nul (for /f "tokens=1 delims==" %%A in ('set SizeGB') do set "%%A=")
  42. rem Флаг обнаружения ошибки в файловой структуре
  43. if defined Dirty set Dirty=
  44.  
  45. :TmpFile
  46. set "TmpFile=%Temp%\%~n0_%random%.txt"
  47. if exist "%TmpFile%" goto TmpFile
  48. >nul copy nul "%TmpFile%" || (set errorlevel=3& goto _Exit)
  49.  
  50. if defined IgnoreError (
  51. echo WARNING: IgnoreError flag is set. Directory sizes may be not reliable.
  52. echo/
  53. )
  54. if not defined Separator set "Separator= "
  55. >nul chcp 65001
  56. for /f "delims=" %%A in ('^(for /r %Root% %%Z in ^(.^) do @echo "%%Z"^) ^& echo :::') do (
  57. if errorlevel 1 goto _Exit
  58. set CurDir=%%~A
  59. setlocal enabledelayedexpansion
  60. if defined Lvl set PrevLvl=!Lvl!
  61. rem Определяем уровень %CurDir%
  62. if "%%~A" == ":::" (
  63. set Lvl=0
  64. ) else (
  65. >"!TmpFile!" echo !CurDir!||(set errorlevel=3& goto _Exit)
  66. for %%A in ("!TmpFile!") do set /a Lvl=%%~zA
  67. >"!TmpFile!" echo !CurDir:\=!||(set errorlevel=3& goto _Exit)
  68. for %%A in ("!TmpFile!") do set /a Lvl-=%%~zA
  69. if not defined Lvl0 set Lvl0=!Lvl!
  70. )
  71. for /f "delims=| tokens=1-4" %%B in ("!Lvl!|!Lvl0!|!CurDir:~,-2!|!PrevLvl!") do (
  72. endlocal
  73. set Lvl=%%B
  74. set Lvl0=%%C
  75. if not _0 == _%%E (
  76. set PrevLvl=%%E
  77. rem (*) Тут можно использовать только численное сравнение, иначе ошибка
  78. rem при работе с уровнями >9
  79. if %%B gtr %%E (for /f %%z in ("") do cd) || rem
  80. if not errorlevel 1 (
  81. rem Текущий каталог не является подкаталогом предыдущего каталога, либо
  82. rem предыдущий каталог был последним.
  83. for /l %%F in (%%E,-1,%%B) do (
  84. rem Чтобы не уйти выше корня при обработке ":"
  85. if %%F geq %%C (
  86. rem Выводим информацию о предыдущем каталоге и всех его предках до
  87. rem уровня текущего включительно
  88. setlocal enabledelayedexpansion
  89. if !SizeGB%%F! gtr 0 (
  90. rem Если размер более 1 GB, значение SizeB нужно дополнить слева
  91. rem нулями.
  92. set SizeB%%F=00000000!SizeB%%F!
  93. echo !Name%%F!!Separator!!SizeGB%%F!!SizeB%%F:~-9!
  94. ) else (
  95. echo !Name%%F!!Separator!!SizeB%%F!
  96. )
  97. endlocal
  98. rem Стираем переменные
  99. set SizeB%%F=
  100. set SizeGB%%F=
  101. )
  102. )
  103. )
  104. )
  105. if not _%%B == _0 (
  106. if defined IgnoreError (
  107. set /a 0
  108. ) else (
  109. rem Пытаемся прочесть содержимое текущего каталога
  110. >nul 2>&1 (dir /b "%%D\?" || dir /b /ah "%%D\?" || dir /b /as "%%D\?")
  111. )
  112. if errorlevel 1 (
  113. echo/
  114. echo Error processing directory %%D.
  115. goto _Exit
  116. ) else (
  117. (for /f "eol= delims=" %%F in ('2^>nul dir /b /a-d "%%D\*"') do (
  118. for %%G in ("%%D\%%F") do (
  119. set Size=%%~zG
  120. if not defined Size (
  121. rem Повреждение файловой структуры
  122. if not defined Dirty set Dirty=1
  123. rem Получаем размер через dir
  124. (for /f %%z in ("") do cd) || rem
  125. for /f "skip=5 tokens=3" %%H in ('dir /-c "%%D\%%F"') do (
  126. if errorlevel 1 set Size=%%H
  127. )
  128. (for /f %%z in ("") do cd) || rem
  129. )
  130. setlocal enabledelayedexpansion
  131. if not "" == "!Size:~,-9!" (
  132. rem Размер текущего файла > 1 GB
  133. set /a SizeGB%%B+=!Size:~,-9!
  134. if !SizeGB%%B! lss 0 (set errorlevel=4& goto _Exit)
  135. set Size=!Size:~-9!
  136. rem Убираем ведущие нули у Size
  137. for /l %%H in (0,1,7) do (
  138. if not errorlevel 1 if not "!Size:~%%H,1!" == "0" (
  139. set Size=!Size:~%%H!
  140. (for /f %%z in ("") do cd) || rem
  141. )
  142. )
  143. )
  144. set Size=!Size:~-9!
  145. set /a SizeB%%B+=!Size!
  146. set /a SizeGB%%B+=SizeB%%B/1000000000,SizeB%%B%%=1000000000
  147. if !SizeGB%%B! lss 0 (set errorlevel=4& goto _Exit)
  148. for /f "tokens=1,2" %%H in ("!SizeB%%B! !SizeGB%%B!") do (
  149. endlocal
  150. set SizeB%%B=%%H
  151. set SizeGB%%B=%%I
  152. )
  153. )
  154. )) || (
  155. rem В текущем каталоге нет файлов
  156. set SizeB%%B=0
  157. set SizeB%%GB=0
  158. )
  159. )
  160. )
  161. for /l %%F in (%%B,-1,%%C) do (
  162. if not %%F == %%B (
  163. rem Увеличиваем значения size-переменных для всех предков текущего
  164. rem каталога на его размер
  165. set /a SizeB%%F+=SizeB%%B
  166. set /a SizeGB%%F+=SizeB%%F/1000000000,SizeB%%F%%=1000000000
  167. set /a SizeGB%%F+=SizeGB%%B
  168. )
  169. )
  170. set Name%%B=%%D
  171. )
  172. )
  173. if defined Dirty (
  174. echo/
  175. echo WARNING: errors in the file system were detected.
  176. )
  177. goto _Exit
  178.  
  179. :_IsFile <obj>
  180. rem Exit codes:
  181. rem 2: <obj> does not exist
  182. rem 1: <obj> is a directory
  183. rem 0: <obj> is a file
  184. rem -1: Invalid syntax
  185. :_IsDir <obj>
  186. rem Exit codes:
  187. rem 2: <obj> does not exist
  188. rem 1: <obj> is a file
  189. rem 0: <obj> is a directory
  190. rem -1: Invalid syntax
  191. setlocal disabledelayedexpansion
  192. if /i "%0" == ":_IsFile" (
  193. set not=not
  194. ) else (
  195. if defined not set not=
  196. )
  197. set Obj=%1
  198. if defined Obj if not "" == "%Obj:"=%" goto $endif
  199. echo/
  200. echo Usage:
  201. echo call %0 ^<obj^>
  202. exit /b -1
  203. :$endif
  204. if not "%Obj:"=%" == "%Obj:"=@%" set "Obj=%Obj:"=%"
  205. if not "%Obj:?=%" == "%Obj%" exit /b 2
  206. if not exist "%Obj%" exit /b 2
  207. for %%A in ("%Obj%") do set Attr=%%~aA
  208. if /i %not% "-" == "%Attr:~,1%" exit /b 1
  209. exit /b
  210.  
  211. :_Help
  212. echo Calculates sizes of each directory in the directory tree.
  213. echo/
  214. echo Usage:
  215. echo %~nx0 ^<root^>
  216. echo/
  217. echo Exit codes: 0 OK
  218. echo 1 Error processing directory
  219. echo 2 %Error2%
  220. echo 3 General error
  221. echo 4 %Error4%
  222. echo -1 Invalid syntax
  223. set errorlevel=-1
  224.  
  225. :_Exit
  226. if defined Error%errorlevel% (
  227. set errorlevel=%errorlevel%
  228. if not "!!" == "" setlocal enabledelayedexpansion
  229. echo !Error%errorlevel%!.
  230. )
  231. if "!!" == "" endlocal
  232. (
  233. for %%A in ("%TmpFile%" "%TmpFile2%" "%TmpFile3%") do if exist %%A del %%A
  234. echo/
  235. echo Exit code: %errorlevel%
  236. rem if %errorlevel% gtr 0 pause
  237. exit /b %errorlevel%
  238. )
  239.  
  240. Переменные с <lvl> в имени всегда содержат информацию по ветви текущего
  241. обрабатываемого каталога.
  242. Переменная вида Name<lvl> содержит имя каталога уровня <lvl>.
  243. Переменные вида SizeB<lvl> и SizeGB<lvl> содержат текущий подсчитанный размер
  244. каталога уровня <lvl> - часть меньше GB и целые GB соответственно.
  245. Напр., если %Root% = C:\foo, то после обработки C:\foo\bar\data имеем:
  246. Lvl = 2 (относительный уровень)
  247. Name2= C:\foo\bar\data
  248. SizeB2 = <суммарный размер файлов в C:\foo\bar\data за вычетом целых GB>
  249. SizeGB2 = <суммарный размер файлов в C:\foo\bar\data в целых GB>
  250. Name1= C:\foo\bar
  251. SizeB1 = <суммарный размер файлов в C:\foo\bar и уже обработанных его
  252. подкаталогов за вычетом целых GB + SizeB2>
  253. SizeGB1 = <суммарный размер файлов C:\foo\bar и уже обработанных его
  254. подкаталогов в целых GB + SizeGB2>
  255. Name0 = C:\foo
  256. SizeB0 = <суммарный размер файлов в C:\foo и уже обработанных его подкаталогов
  257. за вычетом целых GB + SizeB2>
  258. SizeGB0 = <суммарный размер файлов C:\foo и уже обработанных его подкаталогов в
  259. целых GB + SizeGB2>
  260. Под "уже обработанными" подразумеваются каталоги, пройденные по всей глубине
  261. уровней.
  262. При обработке следующего каталога - C:\foo\bar2 - на экран будут выведены
  263. данные по каталогам:
  264. C:\foo\bar\data
  265. C:\foo\bar
  266. Затем будут уничтожены <lvl>-переменные с <lvl> = 1 и 2. И наконец:
  267. Lvl = 1
  268. заново определены Name1, SizeB1 и SizeGB1, пересчитаны SizeB0 и SizeGB0.
  269.  
  270. Changelog
  271. v1.0.12
  272. [+] Поддержка юникодных имен.
  273. [+] Сообщаем об обнаружении ошибок в файловой структуре.
  274. [*] Улучшена обработка ошибок.
  275.  
  276. v1.0.10
  277. [+] Настраиваемый разделитель имени и размера. Устанавливается переменной внутри скрипта.
  278.  
  279. v1.0.9
  280. [+] Поддержка флага IgnoreError - если установлен, то ошибки при чтении содержимого каталогов (из-за юникодных символов в имени или недостаточных прав доступа) игнорируются. Устанавливается переменной внутри скрипта.
  281. [-] Неправильно обрабатывались каталоги уровнем 10 и глубже.
  282. [-] Пропускались каталоги с атрибутами Hidden и/или System.
  283. [+] Показываются сведения о скрипте в начале работы и код ошибки в конце.
  284. [+] Краткое описание алгоритма в конце скрипта.
  285.  
  286. v1.0.3
  287. [*] Initial public release.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement