Форум программистов, компьютерный форум, киберфорум
Batch (CMD/BAT)
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.76/21: Рейтинг темы: голосов - 21, средняя оценка - 4.76
 Аватар для eva2326
1673 / 501 / 107
Регистрация: 17.05.2015
Сообщений: 1,519

[оптимизация] обрезка файловых путей с конца

07.02.2019, 14:00. Показов 5197. Ответов 20
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Всем привет!

Подскажите, как можно оптимизировать приведенные ниже батники.


--------
Для отладочных целей необходимо выводить некоторую диагностическую информацию.
В частности: файловые пути.

Но пути часто оказываются слишком избыточно длинные.
И это портит читабельность логов.
Поэтому, возникла потребность укоротить файловые пути с конца.
Что бы отображать не весь путь, а только часть.
Например, отображаем только 5 последних родительских каталогов.

Для этого я построила батник.
Он полностью рабочий, и иллюстрирует нужное на практике:

Windows Batch file
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
@echo off
cls
 
@echo.
@echo.
 
call :cutPath "C:\test1\test2\test3\test4\test5\test6\test7" "5" "mypath" 
@echo [mypath] '%mypath%'
exit /b
 
rem =========================================================================
rem =========================================================================
 
:cutPath
   ::%~1 path
   ::%~2 count last legs
   ::%~3 variable name 
   ::%~4 symbol slash. by default '\'
 
   if "%~3" == "" (
       @echo [ERROR] name of return value is not specified
       exit /b 1
   )
   if %~2 lss 0 (
       @echo [ERROR] number of legs of path can not be less than zero
       exit /b 1
   )
   if %~2 equ 0 (
       set "%~3="
       exit /b
   )
   if "%~1" == "" (
       set "%~3="
       exit /b
   )
   if "%~4" == "" (set "slash=\") else (set "slash=%~4")
 
   call :enumLegPath "%~1"
 
   if %count% equ 0 (
       set "%~3="
       exit /b
   )
 
   set /a "front=%count%-%~2"
 
   if %front% lss 0 (set front=0)
 
   set "result="
   for /l %%i in (%front%, 1, %back%) do (
       call :accumulateLeg "%%i"
   )
 
   set "front=%result:~0,1%"
   if "%front%" == "%slash%" (set "result=%result:~1%")
 
   set "%~3=%result%"
exit /b
 
rem =========================================================================
rem =========================================================================
 
:accumulateLeg
    :: %~1  index of aray
    call set "leg=%%array[%~1]%%"
    rem @echo [leg][%~1] '%leg%'
    set "result=%result%%slash%%leg%"
exit /b
 
rem =========================================================================
rem =========================================================================
 
:enumLegPath
    set "back=0"
    set "count=0"
    set "enumerator=%~1"
:loopEnumLegPath
    for /F "tokens=1* delims=/\" %%g in ("%enumerator%") do (
        set "enumerator=%%h"
        rem @echo [-1-] '%%g'
        call :processLegPath "%%g"
    )
    if "%enumerator%" neq "" (goto :loopEnumLegPath)
 
    set /a "back=%count%-1"
exit /b 0
 
rem =========================================================================
rem =========================================================================
 
:processLegPath
    rem @echo [-2-] %~1
    set "array[%count%]=%~1"
    set /a "count +=1"
exit /b
 
rem =========================================================================
rem =========================================================================
Функциональность и дизайн использования - именно то, что нужно.
Одна проблема - уж слишком он медленно работает.

Проблема усугубляется тем,
что исходные файловые пути могут быть взяты черти откуда,
и записаны черти как.

Поэтому, прежде чем использовать такие пути, их необходимо нормализировать.
Для нормализации я написала вот такой скрипт:

Windows Batch file
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
rem =========================================================================
rem =========================================================================
 
rem usage:
rem call :normalizePath "C:\111\222\333\..\..\555" "normalized"
rem @echo [normalized] '%normalized%'
 
:normalizePath
    set "RETVAL=%~dpfn1"
    set "VARIABLE_NAME=%~2"
    call :removeEndedSlash 
    set "%VARIABLE_NAME%=%RETVAL%"
exit /b
 
rem =========================================================================
rem =========================================================================
 
:removeEndedSlash
    set "last=%RETVAL:~-1%"
 
    if "%last%" == "\" (
        set "RETVAL=%RETVAL:~0,-1%"
        goto :removeEndedSlash
    )
    if "%last%" == "/" (
        set "RETVAL=%RETVAL:~0,-1%"
        goto :removeEndedSlash
    )
exit /b
 
rem =========================================================================
rem =========================================================================
Данный батник должен удалить из файлового пути все управляющие ".."/"." точечки.
А так же, удалить лишние слэши в конце строки.

Он все делает замечательно, но тоже добавляет тормозов.

В реальных условиях достаточно много файловых путей,
которые что бы красиво вывести в лог,
нужно предварительно обрабатывать.

Но мои скрипты слишком медленные!
С ними конечно логи намного красивее,
Но их использование привело к серьёзному замедлению выполнения наших процедур.


Можно ли, сохранив дизайн использования моих батников, как то ускорить их работу?

Важно:
Известно, что на машинках, где запускаются скрипты,
может и не быть прав для запуска скриптов повер-шелла.
0
Лучшие ответы (1)
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
07.02.2019, 14:00
Ответы с готовыми решениями:

Преобразование файловых путей в древовидный вид
Привет, есть пути к неким файлам. "Qt\\Docs\\Qt-5.4\\1.exe" "Qt\\Docs\\Qt-5.4\\2.exe" "Qt\\Docs111\\Qt-5.4\\2.exe" ...

Обрезка полных путей файлов
У меня есть директория. Хочу получить список всех файлов в поддиректориях. Делаю так: FileInfo files = dir.GetFiles("*.*",...

Парсинг путей в дерево. Оптимизация
Доброго времени суток. Имеем код : void PopulateTreeView(TreeView treeView, IEnumerable<string> paths, char pathSeparator) { ...

20
 Аватар для v_svitere
774 / 423 / 137
Регистрация: 03.06.2009
Сообщений: 1,223
Записей в блоге: 4
07.02.2019, 14:30
eva2326,

Важно:
Известно, что на машинках, где запускаются скрипты,
может и не быть прав для запуска скриптов повер-шелла.
Это обходится на раз-два параметром -exec bypass, если вы о политике выполнения сценариев.

Добавлено через 7 минут
А так в целом, для Powershell, это задача на 1 строку кода.
1
4340 / 2130 / 661
Регистрация: 26.04.2015
Сообщений: 6,823
07.02.2019, 16:24
eva2326,
1.
Windows Batch file
1
2
3
4
5
@echo off
set "cutPath=C:\test1\test2\test3\test4\test5\test6\test7"
 
for /f "tokens=1-6 delims=\" %%a in ("%cutPath%") do if not "%%f"=="" (echo "%%a\%%b\%%c\%%d\%%e\%%f") else (echo "%cutPath%")
pause
2.
Windows Batch file
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@echo off
set "sdir=C:\papka"& if not "%~1"=="" set "sdir=%~1"
set ur=3
 
for /f "delims=" %%a in ('dir /ad/b/s "%sdir%"') do set "d=%%a"& call :# "%%d:%sdir%\=%%"
pause& exit
 
:#
 setlocal enabledelayedexpansion
  set "d=%~1"
  for %%a in ("%d:\=" "%") do set /a n+=1& if !n! leq %ur% set "cP=!cP!\%%~a"
  echo "%sdir%%cP%"
 endlocal
exit /b
Добавлено через 24 минуты
3.
Windows Batch file
1
2
3
4
5
6
7
8
9
10
@echo off
set "cutPath=C:\111\222\333\..\..\555"
 
for %%a in ("%cutPath:\=" "%") do set /a n+=1& echo %%~a|>nul findstr /xv /c:"\." /c:"\.\." && call :# "%%n%%" "%%~a"
echo:
pause& exit
 
:#
 if %~1 leq 5 <nul set /p="%~2\"
exit /b
2
 Аватар для KDE777
1886 / 1108 / 428
Регистрация: 22.01.2016
Сообщений: 3,050
07.02.2019, 17:22
v_svitere, уже справедливо заметил, что -ExecutionPolicy Bypass позволяет запускать ps-скрипты в обход настроенной по умолчанию политики:

Windows Batch file
1
PowerShell.exe -ExecutionPolicy Bypass -File "C:\Scripts\script01.ps1"
Поэтому, просто для примера:

Цитата Сообщение от eva2326 Посмотреть сообщение
Что бы отображать не весь путь, а только часть.
Например, отображаем только 5 последних родительских каталогов.
PowerShell
1
2
$n = 5; $path = "C:\test1\test2\test3\test4\test5\test6\test7"
([REGEX]::Match($path,"(\\[^\\]+){1,$n}\\?$")).value
Code
1
\test3\test4\test5\test6\test7
Добавлено через 7 минут
Цитата Сообщение от eva2326 Посмотреть сообщение
удалить из файлового пути все управляющие ".."/"." точечки.
А так же, удалить лишние слэши в конце строки.
PowerShell
1
'C:\111\222\333\..\..\555\' -replace '(\\\.\.)|\\$'
Code
1
C:\111\222\333\555
2
 Аватар для v_svitere
774 / 423 / 137
Регистрация: 03.06.2009
Сообщений: 1,223
Записей в блоге: 4
07.02.2019, 17:22
Еще можно обычными split/join обойтись, хотя мне больше нравятся регулярки.
PowerShell
1
"C:\test1\test2\test3\test4\test5\test6\test7".split("\")[-5..-1] -join "\"
3
Любознательный
 Аватар для YuS_2
7406 / 2256 / 360
Регистрация: 10.03.2016
Сообщений: 5,216
07.02.2019, 18:26
Цитата Сообщение от eva2326 Посмотреть сообщение
Для отладочных целей необходимо выводить некоторую диагностическую информацию.
В частности: файловые пути.
...
Что бы отображать не весь путь, а только часть.
Например, отображаем только 5 последних родительских каталогов.
Windows Batch file
1
2
3
4
5
6
@echo off
set "pth=C:\test1\test2\test3\test4\test5\test6\test7"
set lvl=5
for /f "delims=" %%i in ('powershell -ex bypass -c "&{-join ('%pth%' -split '(\\)')[0..(%lvl%*2)]}"') do set "splpth=%%~i"
echo [%splpth%]
pause
2
 Аватар для eva2326
1673 / 501 / 107
Регистрация: 17.05.2015
Сообщений: 1,519
08.02.2019, 17:53  [ТС]
Цитата Сообщение от alpap Посмотреть сообщение
1.
интересное решение)

Цитата Сообщение от alpap Посмотреть сообщение
2.
зависание.

Цитата Сообщение от alpap Посмотреть сообщение
3.
- не дает выигрыша по скорости по сравнению с моим батником.
- работает не правильно.

путь: C:\111\222\333\..\..\555
нормализировал вот так: C:\111\222\333\
а должен был так: C:\111\555


Цитата Сообщение от KDE777 Посмотреть сообщение
\test3\test4\test5\test6\test7
ни в начале, ни в конце не должно быть никаких слэшей.

Цитата Сообщение от KDE777 Посмотреть сообщение
'C:\111\222\333\..\..\555\' -replace '(\\\.\.)|\\$'
Цитата Сообщение от KDE777 Посмотреть сообщение
C:\111\222\333\555
Это же файловый путь!!! )))
Нельзя просто так брать и вырезать точечки.
Путь же сделается уже не правильным!!!

Две точки - значит нужно подняться на уровень вверх.
После нормализации получится: C:\111\555

Цитата Сообщение от v_svitere Посмотреть сообщение
Еще можно обычными split/join обойтись, хотя мне больше нравятся регулярки.
Мерси

Простой сплит всегда лучше регулярки.
Проще для понимания, и работает в десятки раз быстрее
(если не в сотни)

Цитата Сообщение от YuS_2 Посмотреть сообщение
for /f "delims=" %%i in ('powershell -ex bypass -c "&{-join ('%pth%' -split '(\\)')[0..(%lvl%*2)]}"') do set "splpth=%%~i"

- работает оооочееееень медленно.
подозреваю, что повершелл очень медленно взлетает.

- не правильно работает.
отрезал путь сначала.
а должен был с конца.
0
Любознательный
 Аватар для YuS_2
7406 / 2256 / 360
Регистрация: 10.03.2016
Сообщений: 5,216
08.02.2019, 21:23
Цитата Сообщение от eva2326 Посмотреть сообщение
- работает оооочееееень медленно.
подозреваю, что повершелл очень медленно взлетает.
смотрите скрин работы батника.
время работы 1 сек., если это ооооочеееень медленно... тогда да.

Цитата Сообщение от eva2326 Посмотреть сообщение
- не правильно работает.
отрезал путь сначала.
а должен был с конца.
Начало пути, в стандартной последовательности и в нашей реальности, должно считаться от корня диска, а конец пути - собственно, файл/конечный каталог... хотя, конечно, предполагаю, что реальностей может существовать больше чем одна.
Миниатюры
[оптимизация] обрезка файловых путей с конца  
0
4340 / 2130 / 661
Регистрация: 26.04.2015
Сообщений: 6,823
08.02.2019, 21:33
Цитата Сообщение от eva2326 Посмотреть сообщение
2. - зависание.
этот код только (ну в таком виде) для реальных путей, не вытащенных из логов, разница будет.

Цитата Сообщение от eva2326 Посмотреть сообщение
путь: C:\111\222\333\..\..\555
нормализировал вот так: C:\111\222\333\
а должен был так: C:\111\555
нигде в вашем задании не было конкретики по этому поводу, как додумал так и сделал.
0
 Аватар для KDE777
1886 / 1108 / 428
Регистрация: 22.01.2016
Сообщений: 3,050
09.02.2019, 17:29
Цитата Сообщение от eva2326 Посмотреть сообщение
ни в начале, ни в конце не должно быть никаких слэшей.
PowerShell
1
2
$n = 5; $path = "C:\test1\test2\test3\test4\test5\test6\test7\"
([regex]::Match($path,"(?:\\[^\\]+){1,$n}\\?$")).value -replace '^\\|\\$'
Code
1
test3\test4\test5\test6\test7
Цитата Сообщение от eva2326 Посмотреть сообщение
Это же файловый путь!!! )))
Нельзя просто так брать и вырезать точечки.
У вас было написано: "Данный батник должен удалить из файлового пути все управляющие ".."/"." точечки. А так же, удалить лишние слэши в конце строки." Мой пример, это и делает, а если нужно, что-то иное, тогда яснее формулируйте задачу...

Цитата Сообщение от eva2326 Посмотреть сообщение
Путь же сделается уже не правильным!!!
По моему, путь полученный в первом скрипте, также далёк от корректного "test3\test4\test5\test6\test7"

Цитата Сообщение от eva2326 Посмотреть сообщение
Две точки - значит нужно подняться на уровень вверх
А что тогда значит одна точка между слэшами "\."?

Добавлено через 1 час 44 минуты
Цитата Сообщение от eva2326 Посмотреть сообщение
Две точки - значит нужно подняться на уровень вверх.
После нормализации получится: C:\111\555
PowerShell
1
2
3
$path = 'C:\111\222\333\..\..\555\'
while ($path -match '(?:\\(?:[^\.]{2}|[^\\]+)\\\.\.)') {$path = $path -replace [regex]::Escape($Matches.Values)}
$path.TrimEnd('\')
Code
1
C:\111\555
PowerShell
1
2
3
4
5
6
7
8
$paths = 'C:\111\222\333\..\555\','C:\111\222\333\..\..\555\','C:\111\222\333\..\..\..\555\'
foreach ($path in $paths)
{
    $new = $path
    while ($new -match '(?:\\(?:[^\.]{2}|[^\\]+)\\\.\.)') {$new = $new -replace [regex]::Escape($Matches.Values)}
    $new = $new.TrimEnd('\')
    "$path -> $new"
}
Code
1
2
3
C:\111\222\333\..\555\ -> C:\111\222\555
C:\111\222\333\..\..\555\ -> C:\111\555
C:\111\222\333\..\..\..\555\ -> C:\555
Добавлено через 19 минут
...
2
Эксперт Python
5438 / 3859 / 1215
Регистрация: 28.10.2013
Сообщений: 9,552
Записей в блоге: 1
09.02.2019, 17:50
Цитата Сообщение от eva2326 Посмотреть сообщение
путь: C:\111\222\333\..\..\555
нормализировал вот так: C:\111\222\333\
а должен был так: C:\111\555
Сделайте сначала нормализацию средствами системы:
PowerShell
1
2
PS POWERSHELL> > [System.IO.Path]::GetFullPath("C:\111\222\333\..\..\555")
C:\111\555
А потом уже что хотите, то и делайте с ним.

Да и смысл изобретать велосипеды, если все уже написано в системных библиотеках:
PowerShell
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$path = "c:\\.\\a\\very\\very\\long\\..\\path\\that\\..\\needs\\to\\be\\..\\shortened\\by\\calling\\the\\PathCompactpathEx"
 
$path = [System.IO.Path]::GetFullPath($path)
Write-Host "NormalizePath:" $path
 
Add-Type @"
using System;
using System.Runtime.InteropServices;
public class WinAPI {
[DllImport("shlwapi.dll", CharSet=CharSet.Auto)]
public static extern bool PathCompactPathExW(
    [Out] System.Text.StringBuilder pszOut, 
    string szPath, 
    int cchMax, 
    int dwFlags);
}
"@ 
$out = New-Object System.Text.StringBuilder 255
$retval = [WinAPI]::PathCompactPathExW($out,$path,30,0)
Write-Host "TrucnatePath:" $out.ToString()
Code
1
2
NormalizePath: c:\a\very\very\path\needs\to\shortened\by\calling\the\PathCompactpathEx
TruncatePath: c:\a\ver...\PathCompactpathEx
5
 Аватар для eva2326
1673 / 501 / 107
Регистрация: 17.05.2015
Сообщений: 1,519
10.02.2019, 20:19  [ТС]
Цитата Сообщение от YuS_2 Посмотреть сообщение
время работы 1 сек., если это ооооочеееень медленно... тогда да.
Конечно медленно. Целая секунда на один только путь.

Цитата Сообщение от YuS_2 Посмотреть сообщение
Начало пути, в стандартной последовательности и в нашей реальности
В моей реальности была задача:

Цитата Сообщение от eva2326 Посмотреть сообщение
Для отладочных целей необходимо выводить некоторую диагностическую информацию.
В частности: файловые пути.
Но пути часто оказываются слишком избыточно длинные.
И это портит читабельность логов.
Поэтому, возникла потребность укоротить файловые пути с конца.
Что бы отображать не весь путь, а только часть.
Например, отображаем только 5 последних родительских каталогов.
Цитата Сообщение от KDE777 Посмотреть сообщение
У вас было написано: "Данный батник должен удалить из файлового пути все управляющие ".."/"." точечки. А так же, удалить лишние слэши в конце строки." Мой пример, это и делает, а если нужно, что-то иное, тогда яснее формулируйте задачу...

Цитата Сообщение от alpap Посмотреть сообщение
нигде в вашем задании не было конкретики по этому поводу
Это разве не достаточно конкретно?

Цитата Сообщение от eva2326 Посмотреть сообщение
Поэтому, прежде чем использовать такие пути, их необходимо нормализировать.
Цитата Сообщение от eva2326 Посмотреть сообщение
Данный батник должен удалить из файлового пути все управляющие ".."/"." точечки.
А так же, удалить лишние слэши в конце строки.

Не по теме:

Мне казалось, любой человек, который имеет дело в файловыми путями,
знает, как правильно нормализовывать (удалять управляющие точечки) файловый путь



Цитата Сообщение от KDE777 Посмотреть сообщение
По моему, путь полученный в первом скрипте, также далёк от корректного "test3\test4\test5\test6\test7"
Допустим есть путь:
"C:\test1\test2\test3\test4\test55\..\test5\test6\test7"

Нормализуем:
"C:\test1\test2\test3\test4\test5\test6\test7"

Укорачиваем:
"test3\test4\test5\test6\test7"

Получаем вполне себе корректный относительный путь.

Без нормализации получилось бы:
"test55\..\test5\test6\test7"

Что не очень красиво в логах.
Но такой путь по прежнему остается корректным.

Если же просто так вырезать управляющие точки:
"C:\test1\test2\test3\test4\test55\test5\test6\test7"
То уже получаем невалидный путь.
Который может вести в несуществующий каталог.
Или, что ещё хуже, в существующий, но не тот, куда ведет оригинальный путь.

Не по теме:

Вы не задумались, зачем вообще может быть нужен путь,
который после такого варварского вырезания уже нельзя использовать?


Цитата Сообщение от KDE777 Посмотреть сообщение
А что тогда значит одна точка между слэшами "\."?
Одна точечка означает текущий каталог.

Вот эти два пути ведут в один и тот же каталог:
C:\work\example
C:\work\.\example

Цитата Сообщение от Garry Galler Посмотреть сообщение
Да и смысл изобретать велосипеды, если все уже написано в системных библиотеках:
Они не доступны из батника.
А запускать повер-шелл для обработки отдельного пути получается ещё медленнее,
чем велосипед на bat
0
Любознательный
 Аватар для YuS_2
7406 / 2256 / 360
Регистрация: 10.03.2016
Сообщений: 5,216
10.02.2019, 20:34
Цитата Сообщение от eva2326 Посмотреть сообщение
Целая секунда
иногда это вечность... да

Цитата Сообщение от eva2326 Посмотреть сообщение
В моей реальности была задача:
Видимо, в Вашей реальности, некоторые термины имеют противоположные значения. Ну, это судя по тому, что в цитате было выделено.
Цитата Сообщение от eva2326 Посмотреть сообщение
укоротить файловые пути с конца
Вы скрин работы сценария здесь посмотрели?
1
Эксперт Python
5438 / 3859 / 1215
Регистрация: 28.10.2013
Сообщений: 9,552
Записей в блоге: 1
10.02.2019, 20:34
Цитата Сообщение от eva2326 Посмотреть сообщение
А запускать повер-шелл для обработки отдельного пути получается ещё медленнее
А не надо запускать для одного пути. Запускайте для всех. И не из батника, а нормального ps1 скрипта c нормальной логикой.
Powershell работает в 100-1000 раз быстрее cmd.
Powershell + C# работает в миллион раз быстрее cmd.
Единственный минус powershell - замедленный холодный старт. Для первичной загрузки командлетов (читай библиотек) требуется при старте интерпретатора несколько секунд. В этом плане cmd, конечно, быстрее.
И это единственное в чем он быстрее.
1
10.02.2019, 20:50

Не по теме:

Цитата Сообщение от eva2326 Посмотреть сообщение
Укорачиваем:
"test3\test4\test5\test6\test7"
Получаем вполне себе корректный относительный путь.
В примере, относительно чего получается этот путь не сохраняется, а поэтому откуда он начинается и чем заканчивается, например мне неведомо. И даже не ясно test7 - это каталог или файл :)

Цитата Сообщение от eva2326 Посмотреть сообщение
Вы не задумались, зачем вообще может быть нужен путь, который после такого варварского вырезания уже нельзя использовать?
Здесь иногда просят реализовать такую удивительную чепуху, что нет не задумывался. Что попросили, для того и показал вариант реализации :)

Цитата Сообщение от eva2326 Посмотреть сообщение
А запускать повер-шелл для обработки отдельного пути получается ещё медленнее,
чем велосипед на bat
Присоединюсь к Garry Galler - пишите сразу всё на PS и избавитесь от множества проблем. В этом году PS 2.0 исполняется уже 10 лет...

0
4340 / 2130 / 661
Регистрация: 26.04.2015
Сообщений: 6,823
11.02.2019, 00:34
и все-таки вариант на cmd
Windows Batch file
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@echo off
set "cutPath=C:\111\222\333\..\..\555\.\666"
:: Будет: C:\111\555\666
::set "cutPath=C:\111\222\333\..\..\555\.\666\777\.\888\999"
:: Будет: 555\666\777\888\999
 
for /f "tokens=2 delims=[]" %%a in ('tree "%cutPath%"^|find /n /v ""^|find "[3]"') do set "sPath=%%a"
for %%a in ("%sPath:\=" "%") do set /a "m2+=1,m1=m2-4"& call set "$%%m2%%=%%~a"
if %m2% geq 5 (
 for /l %%n in (%m1% 1 %m2%) do call >>+<+ set /p z="%%$%%n%%\"
 del+& call :# "%%z:~,-1%%"
) else (
 call :# "%sPath%"
)
pause& exit
 
:#
 echo %~1
exit /b
4
 Аватар для b0gus
741 / 339 / 134
Регистрация: 17.03.2014
Сообщений: 842
11.02.2019, 00:50
alpap, можете прокомментировать трюк?
Windows Batch file
1
for ... do call >>+<+ set /p z="%%$%%n%%\"
1
 Аватар для volodin661
6799 / 2298 / 349
Регистрация: 10.12.2013
Сообщений: 7,924
11.02.2019, 04:28
Цитата Сообщение от eva2326 Посмотреть сообщение
Это же файловый путь!!! )))
Нельзя просто так брать и вырезать точечки.
Путь же сделается уже не правильным!!!
После акта кастрации в целях торжества КРАСОТЫ файловый путь неизбежно станет неправильным,
поэтому вырезать из него и дорисовывать к нему можно всё, что угодно, лишь бы красиво и информативно.


C:「folder-A」 ✄ 「temp21」「18012018」
C:「folder-B」 ✄ 「..」「01022019」
2
4340 / 2130 / 661
Регистрация: 26.04.2015
Сообщений: 6,823
11.02.2019, 11:24
b0gus, сначала дозапись в tmp (+) каждой $%%n (в одну строку с дописыванием \ при каждой операции, поэтому последний приходиться удалять ниже), как закончились - считывание оттуда же первой и единственной строки в z.

eva2326,
Кстати вариант без временного файла:
Windows Batch file
1
2
3
4
5
6
7
8
9
@echo off
set "cutPath=C:\111\222\333\..\..\555\.\666"
::set "cutPath=C:\111\222\333\..\..\555\.\666\777\.\888\999"
 
for /f "tokens=2 delims=[]" %%a in ('tree "%cutPath%"^|find /n /v ""^|find "[3]"') do set "sPath=%%a"
for %%a in ("%sPath:\=" "%") do set /a "mN+=1,m1=mN-4,m2=mN-3,m3=mN-2,m4=mN-1"& call set "$%%mN%%=%%~a"
if %mN% geq 5 (call set "$P=%%$%m1%%%\%%$%m2%%%\%%$%m3%%%\%%$%m4%%%\%%$%mN%%%") else (set "$P=%sPath%")
echo %$P%
pause& exit
2
 Аватар для eva2326
1673 / 501 / 107
Регистрация: 17.05.2015
Сообщений: 1,519
11.02.2019, 22:24  [ТС]
Цитата Сообщение от alpap Посмотреть сообщение
Кстати вариант без временного файла:
Спасибо!

Почти-почти то, что нужно.
Но у меня к вам есть два вопроса:

1.
Почему у вас такая неоптимально-медленная нормализация?

Вот здесь получается тяжелый запуск:
Windows Batch file
1
for /f "tokens=2 delims=[]" %%a in ('tree "%cutPath%"^|find /n /v ""^|find "[3]"') do set "sPath=%%a"
Ведь можно же гораздо проще и быстрее:
Если передать управление процедуре:
Windows Batch file
1
2
3
4
5
6
:cutPath
    set "normalized=%~dpfn1"
    if %normalized:~-1%==\ (
        set "normalized=%normalized:~0,-1%"
    )
exit /b
То путь автоматически нормализуется:
Windows Batch file
1
set "normalized=%~dpfn1"
Ещё, обратите внимание на "trailing slash" (слэш в окончании пути)
Если его не удалить, то работать будет не правильно.
(не правильно подсчитает количество колен)
И вообще, он чаще мешается, чем помогает.

Поэтому, приходится затрачивать дополнительное время на дополнительную проверку:
Windows Batch file
1
2
3
    if %normalized:~-1%==\ (
        set "normalized=%normalized:~0,-1%"
    )
2.
У вас основная логика выполняется:
Windows Batch file
1
2
3
4
5
6
7
8
9
10
    for %%a in ("%normalized:\=" "%") do (
        set /a "mN+=1,m1=mN-4,m2=mN-3,m3=mN-2,m4=mN-1" & (
            call set "$%%mN%%=%%~a"
        )
    )
    if %mN% geq 5 (
        call set "%~2=%%$%m1%%%\%%$%m2%%%\%%$%m3%%%\%%$%m4%%%\%%$%mN%%%"
    ) else (
        set "%~2=%normalized%"
    )
Интересная конструкция )))
И работает быстро.
Но это - хардкорд до пятого колена.

Можно ли как то сделать так, что бы работало так же быстро,
Но можно было бы задавать произвольное количество колен?
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
11.02.2019, 22:24
Помогаю со студенческими работами здесь

Типы оптимизация: черная оптимизация, серая оптимизация и белая оптимизация
Много много лет назад, на заре становления профессии &quot;оптимизатора&quot; в какой то умной книжке был создан миф. Это миф о цветовой индефикации...

Поиск конца абзаца и конца материала
Как в конце файла Word (в конце всего текста) поменять два подряд идущих конца абзаца (¶) на один? В любом другом месте текста всё...

Рекурсивная функция, которая выведет массив с конца (переворачивать массив не нужно, просто вывод элементов с конца)
Рекурсивная функция, которая выведет массив с конца (переворачивать массив не нужно, просто вывод элементов с конца)

Файловых типов данных
Помогите пожалуйста с лабораторной по информатике плиз : Дан файл f, компоненты которого являются действительными числами. Найти...

Сортировка файловых записей
Дан фаил,содержащий сведения о товарах. В каждой записи определены следующие поля: - название - цена -...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
Модель ЗдрввоСохранения 7: больше работников, больше ресурсов.
anaschu 08.04.2026
работников и заданий может быть сколько угодно, но настроено всё так, что используется пока что только 20% kYBz3eJf3jQ
Дальние перспективы сервера - слоя сети с космологическим дизайном интефейса карты и логики.
Hrethgir 07.04.2026
Дальнейшее ближайшее планирование вывело к размышлениям над дальними перспективами. И вот тут может быть даже будут нужны оценки специалистов, так как в дальних перспективах всё может очень сильно. . .
Горе от ума
kumehtar 07.04.2026
Эта мне ментальная установка, что вот прямо сейчас, мол, мне для полного счастья не хватает (нужное вписать), и когда я этого достигну - тогда и полный кайф. Одна из самых сильных ловушек на пути. . . .
Использование значений реквизитов справочника в документе, с определенными условиями и правами
Maks 07.04.2026
1. Контроль срока действия договора Алгоритм из решения ниже реализован на примере нетипового документа "ЗаявкаНаРаботу", разработанного в конфигурации КА2. Задача: уведомлять пользователя, если. . .
Доступность команды формы по условию
Maks 07.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "СписаниеМатериалов", разработанного в конфигурации КА2. Задача: сделать доступной кнопку (команда формы "ЗавершитьСписание") при. . .
Уведомление о неверно выбранном значении справочника
Maks 06.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "НарядПутевка", разработанного в конфигурации КА2. Задача: уведомлять пользователя, если в документе выбран неверный склад. . .
Установка Qt Creator для C и C++: ставим среду, CMake и MinGW без фреймворка Qt
8Observer8 05.04.2026
Среду разработки Qt Creator можно установить без фреймворка Qt. Есть отдельный репозиторий для этой среды: https:/ / github. com/ qt-creator/ qt-creator, где можно скачать установщик, на вкладке Releases:. . .
AkelPad-скрипты, структуры, и немного лирики..
testuser2 05.04.2026
Такая программа, как AkelPad существует уже давно, и также давно существуют скрипты под нее. Тем не менее, прога живет, периодически что-то не спеша дополняется, улучшается. Что меня в первую очередь. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru