Компьютерный форум OSzone.net  

Компьютерный форум OSzone.net (http://forum.oszone.net/index.php)
-   Скриптовые языки администрирования Windows (http://forum.oszone.net/forumdisplay.php?f=102)
-   -   Выделить подстроки из текстового файла и записать их в пару переменных (http://forum.oszone.net/showthread.php?t=350568)

HankHank 27-01-2022 11:16 2978770

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

Возникла задача, связанная с обработкой текстового файла.

Предыстория в следующих двух абзацах. Её можно пропустить.

Фонотека на дисках USB HDD структурирована определённым образом. В ней используются точки соединения - JUNCTION. Изначально предполагалось работать с этими дисками, монтируя тома каждый раз на букву “H:”.
Однако, спустя время, с монтированием заморачиваться поднадоело.
И для этого в файловой системе NTFS появились относительные символьные ссылки – SYMLINKD.
Процедура замены JUNCTION на SYMLINKD понятна. Для этого есть соответствующая команда NTLinks Maker http://wincmd.ru/plugring/NTLinksMaker.html .
Также понятно, как вывалить информацию обо всех JUNCTION в файл:

@chcp 1251 >nul
dir /AL /S H:\ >JtoS.txt

В итоге файл JtoS.txt содержит регулярную структуру данных. Например:

Код:

Том в устройстве H имеет метку 2 NTFS
 Серийный номер тома: CAE4-9F0A


 Содержимое папки H:\Слушать\Слушать\ Инструменты\Труба (trumpet)

09.12.2010  23:43    <JUNCTION>    Baldauf Rudiger [\??\H:\Фонотека\Jazz - fusion\Baldauf Rudiger]
29.10.2011  02:21    <JUNCTION>    Beiderbecke Leon Bix [\??\h:\Фонотека\Jazz\Beiderbecke Leon Bix]
...
              0 файлов              0 байт
...

 Содержимое папки H:\Слушать\Слушать\Modern jazz

09.10.2010  08:28    <JUNCTION>    Lloyd Charles [\??\H:\Фонотека\Jazz - avant-guard\Lloyd Charles]
              0 файлов              0 байт

 Содержимое папки H:\Слушать\Слушать\Smooth

23.08.2010  21:29    <JUNCTION>    Blake Aaron - Desire (2007) [\??\H:\Фонотека\Jazz - smooth\Aaron Blake\Blake Aaron - Desire (2007)]
02.09.2010  18:56    <JUNCTION>    Club des Belugas - Swop (2008) [\??\H:\Фонотека\Jazz - smooth\ Various\Club des Belugas - Swop (2008)]
...
              0 файлов              0 байт

    Всего файлов:
              1 файлов              0 байт
            665 папок  316*940*726*272 байт свободно

Очевидно, что вся информация, нужная для реорганизации дисков, присутствует.

Формально нужно организовать цикл по секциям, начинающимся со строк “Содержимое папки”.
В каждой секции пройти по строкам, содержащим “<JUNCTION>”, каждый раз в переменную %t помещая содержимое квадратных скобок без символов “\??\” (целевой объект), а в переменную %l – ссылку.

Для первого вхождения:
%t = “H:\Фонотека\Jazz - fusion\Baldauf Rudiger”,
%l = “H:\Слушать\Слушать\ Инструменты\Труба (trumpet)\Baldauf Rudiger”.
Для второго вхождения:
%t = “h:\Фонотека\Jazz\Beiderbecke Leon Bix”,
%l = “H:\Слушать\Слушать\ Инструменты\Труба (trumpet)\Beiderbecke Leon Bix”.
и т.д.

%t лежит внутри “[\??\ ... ]”.
%l образуется конкатенацией строки, стоящей следом за “Содержимое папки” , бэк-слеша и строки, стоящей между “<JUNCTION>” и строкой ”[\??\“ без лидирующих и замыкающих пробелов.

В именах файлов, кроме русских букв, могут встречаться спецсимволы (,;:_ и т.п.).

Помогите, плиз, с шаблоном обработки.
Саму процедуру замены с удалением JUNCTION и созданием SYMLINKD вставлю в шаблон самостоятельно.

Спасибо заранее.

megaloman 27-01-2022 16:57 2978789

Не думаю, что эта задача может быть надежно реализована в CMD из-за спецсимволов. Попробуйте формальное решение:
Код:

@Echo Off
cls
>nul Chcp  1251
        Set "FileIn=Z:\Box_In\JtoS.txt"

        FOR /F "usebackq delims=" %%s In ("%FileIn%") DO (
                FOR /F "usebackq tokens=3* delims= " %%a In (`Echo "%%s"^|Find /I "Содержимое папки"`) DO (
                        Set "Fold=%%~b"
                        Call Set "Fold=%%Fold:~0,-1%%"
                )
                FOR /F "usebackq tokens=3* delims= " %%a In (`Echo "%%s"^|Find /I "<JUNCTION>"`) DO (
                        Call Set "Junk=%%Fold%%\%%~b"
                        Call Set "Junk=%%Junk:~0,-1%%"
                        Call Set "Junk=%%Junk: [\??\=[%%"
                        FOR /F "usebackq tokens=1,2 delims=[]" %%i In (`Call Echo %%Junk%%`) DO (
rem                                Set "L=%%i"
rem                                Set "T=%%j"
rem                                Call Echo "%%T%%"  &Call Echo "%%L%%"

                                Call :Rezult "%%j" "%%i"
                        )
                )
        )
pause
Exit /B

:Rezult
        Echo %1
        Echo %2
Exit /B

Наверное, удобнее выделенными строками пользоваться внутри процедуры. Я заремил использование переменных в Echo внутри цикла - имхо, это не удобно

DJ Mogarych 27-01-2022 17:41 2978792

Powershell:

Код:

$strNum = ((gc "D:\temp\JtoS.txt" -OutVariable txt |sls 'Содержимое папки').LineNumber|% {$_ - 1})
$strNum += $txt.count
$c = 0

$report = @()
$strNum |% {
$start = $strNum[$c]
$end = $strNum[$c+1] - 1; if ($end -eq -1) {$end = $txt.count}
$piece = ($txt)[$start..$end]
    ($piece) -match '<junction>' |% {
        $obj = [pscustomobject]@{
        t = $_ -replace '.*\\\?\?\\' -replace '\]'
        l = (($piece) -match 'Содержимое папки' -replace '.*папки').trim() + '\' + `
        ($_ -replace '.*<junction>\s+' -replace '\s+\[.*').trim()
        }
    $report += $obj
    }
$c = $c+1
}

Код:

$report

t                                                                l                                                                 
-                                                                -                                                                 
H:\Фонотека\Jazz - fusion\Baldauf Rudiger                        H:\Слушать\Слушать\ Инструменты\Труба (trumpet)\Baldauf Rudiger   
h:\Фонотека\Jazz\Beiderbecke Leon Bix                            H:\Слушать\Слушать\ Инструменты\Труба (trumpet)\Beiderbecke Leon Bix
H:\Фонотека\Jazz - avant-guard\Lloyd Charles                      H:\Слушать\Слушать\Modern jazz\Lloyd Charles                       
H:\Фонотека\Jazz - smooth\Aaron Blake\Blake Aaron - Desire (2007) H:\Слушать\Слушать\Smooth\Blake Aaron - Desire (2007)             
H:\Фонотека\Jazz - smooth\ Various\Club des Belugas - Swop (2008) H:\Слушать\Слушать\Smooth\Club des Belugas - Swop (2008)

Бикс Бейдербек - такое сейчас редко увидишь в фонотеке...

megaloman 27-01-2022 18:29 2978795

HankHank, Не думаю, что хорошая идея копаться в файле. А почему бы сразу не обрабатывать вывод Dir?
Код:

@Echo Off
cls
>nul Chcp  1251
        Set "BoxIn=H:\"
       
        FOR /F "usebackq delims=" %%d In (`2^>nul Dir "%BoxIn%" /AL /S /B`) DO (
                FOR /F "usebackq tokens=1,2 delims=[]" %%i In (`2^>nul Dir /AL "%BoxIn%%%~nxd*.*"^|Find /I "<JUNCTION>"`) DO (
                        Echo.
                        Echo "%%d"
                        Set "L=%%j"
                        Call Set "L=%%L:\??\=%%"
                        Call Echo "%%L%%"
                )
        )
pause
Exit /B

Полноценно не тестировал,

HankHank 27-01-2022 21:05 2978798

Код для скрипта может быть проще, если использовать команду

DIR /AL /B /S H:\

Тогда получим чистые строки с полными путями к ссылкам:

Код:

H:\Слушать\Слушать\Albright Gerald
H:\Слушать\Слушать\Alex Rostotsky - Time when fish think of the past (2004)
H:\Слушать\Слушать\Dave Brubeck - Ken Burns Jazz (Columbia - Legacy Records) 2000
H:\Слушать\Слушать\Dino Saluzzi - El Encuentro (2010) [Flac]
H:\Слушать\Слушать\Modern Jazz Quartet - Live At The Lighthouse (MFSL MFCD 827) (1967)

А, еcли вызвать по ссылке FSUTIL, то получим список строк, в котором нас интересует “Print Name:” - это и будет целевой объект.

Например:

FSUTIL reparsepoint query “H:\Слушать\Слушать\Alex Rostotsky - Time when fish think of the past (2004)”

Код:

Reparse Tag Value : 0xa0000003
Tag value: Microsoft
Tag value: Name Surrogate
Tag value: Mount Point
Substitue Name offset: 0
Substitue Name length: 184
Print Name offset:    186
Print Name Length:    176
Substitute Name:      \??\h:\Фонотека\Jazz\Rostotsky Alex\Alex Rostotsky - Time when fish think of the past (2004)
Print Name:            h:\Фонотека\Jazz\Rostotsky Alex\Alex Rostotsky - Time when fish think of the past (2004)

Таким образом, проблемы со спецсимволами серьёзно сокращаются.

Мне кажется, при таком раскладе шаблон для CMD вполне должен прокатить.

HankHank 28-01-2022 10:13 2978823

Цитата:

Цитата megaloman
Не думаю, что хорошая идея копаться в файле. А почему бы сразу не обрабатывать вывод Dir? »

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

megaloman 28-01-2022 10:33 2978827

Цитата:

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

Тут уж в огороде бузина а в Киеве дядька: отлаживаем скрипт, который удобно отлаживать, а эффективно использовать будем другой, неотлаженный.
Берите скрипт с непосредственной обработкой Dir и натравливайте его на небольшую папку. :)

HankHank 28-01-2022 10:44 2978828

Цитата:

Цитата megaloman
Берите скрипт с непосредственной обработкой Dir и натравливайте его на небольшую папку »

Тоже вариант.
Только обходить вручную весь диск - не лучшая идея.
Плоская "простыня" кажется удобнее.

megaloman 28-01-2022 11:17 2978830

Цитата:

Цитата HankHank
Только обходить вручную весь диск - не лучшая идея. »

Не обходите. Укажите, для отладки, для Dir папочку, например в моём варианте:

Set "BoxIn=H:\Слушать\Слушать\Modern jazz\"
или более обьемную:
Set "BoxIn=H:\Слушать\Слушать\"

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

HankHank 28-01-2022 15:25 2978853

У меня начальные познания о командных файлах. Но CALL-оператор, вроде, вызывает внешний комфайл или передаёт управление внутри того же файла.
Подскажите, в чём фишка употребления CALL в сочетании с другими операторами типа:
Цитата:

Цитата megaloman
Call Set "Junk=%%Junk:~0,-1%%"
Call Echo "%%T%%" &Call Echo "%%L%%" »

?

DJ Mogarych 28-01-2022 15:52 2978859

Цитата:

Цитата HankHank
У меня начальные познания о командных файлах »

Переходите на Powershell тогда лучше сразу. Там решена масса проблем CMD.

megaloman 28-01-2022 18:18 2978874

Цитата:

Цитата HankHank
Подскажите, в чём фишка употребления CALL в сочетании с другими операторами »

Попытаюсь:
Дело в отложенном раскрытии переменных командной строки.
Вот примеры. Проделайте, проанализируйте. Все эти махинации нужны, чтобы в цикле можно было использовать изменяемые значения переменных.
В 111111 Call не применяли, в результате имеем значение Junk до цикла.
В 222222 используем Call для раскрытия значения переменной внутри цикла,
а в 333333 работаем с переменной Junk внутри вызываемой в цикле процедуры.
В 444444 применяем SetLocal EnableDelayedExpansion для раск для раскрытия значения переменной внутри цикла. Там переменная заключается в знаки !Junk!
При этом возможны неприятности: если в значении переменной присутствует !, то получим непредсказуеый результат.
Код:

@Echo Off
cls
Echo. &Echo ----- 111111 Без Call
        Set "Junk="
        For /L %%i In (100001,100000,400000) Do (
                Set "Junk=%%i"
                Set "Junk=%Junk:~0,-1%"
                Echo i=%%i  Junk="%Junk%"
        )
Echo "%Junk%"

Echo. &Echo ----- 222222 C Call
        Set "Junk="
        For /L %%i In (100001,100000,400000) Do (
                Set "Junk=%%i"
                Call Set "Junk=%%Junk:~0,-1%%"
                Call Echo i=%%i  Junk="%%Junk%%"
        )
Echo "%Junk%"

Echo. &Echo ----- 333333 C процедурой
        Set "Junk="
        For /L %%i In (100001,100000,400000) Do Call :MyEcho %%i
Echo "%Junk%"

Echo. &Echo ----- 444444 SetLocal EnableDelayedExpansion
SetLocal EnableDelayedExpansion
        Set "Junk="
        For /L %%i In (100001,100000,400000) Do (
                Set "Junk=%%i"
                Set "Junk=!Junk:~0,-1!"
                Echo i=%%i  Junk="!Junk!"
        )
Echo "%Junk%"
SetLocal DisableDelayedExpansion

Pause
Exit /B

:MyEcho
        Set "Junk=%1"
        Set "Junk=%Junk:~0,-1%"
        Echo i=%1  Junk="%Junk%"
Exit /B

Аналогичные проблемы при работе с переменными внутри If


Время: 04:42.

Время: 04:42.
© OSzone.net 2001-