Управление строкой пути BATCH

Мне нужно обработать полный путь к файлу, т.е. C:\fold1\fold2...\foldN\filename.dat, чтобы отдельно получить папку родительского файла и имя файла, то есть root=C:\fold1\fold2 ...\foldN и файл=имя_файла.dat.

Это потому, что я хочу обобщить вызов программы независимо от того, откуда вы вызываете основной .bat (этот), например, чтобы иметь возможность выполнить pushd для %root% перед вызовом этой конкретной программы.

Я работаю над этим, но получаю стек при позировании line=%%c:

: before remove quotes from %var%
set var=%var:"=%

if exist %temp% (
    if exist %temp%\filepath.txt del %temp%\filepath.txt
    echo %var% > %temp%\filepath.txt
)
for /f "tokens=1,* delims= " %%z in (%temp%\filepath.txt) do (
    set line=%%z
    echo Line writes %line%.
    set root=empty
    goto :processtoken
)

:processtoken
for /f "tokens=1,* delims=\" %%b in ("%line%") do (
    echo %%b
    echo %%c
    set  line=%%c rem this does not work, why??
    echo Now line writes %line%

    if "%root%"= = "empty" (
        echo [INFO] Root is empty, initialising..
        echo %%c
        set root=%%c
    ) else (
        set root=%root%\%%c
    )
    echo Root is %root%
    goto :end
)

Проблема, с которой я сталкиваюсь, заключается в том, что когда я печатаю, чтобы увидеть, как изменилась %line%, она показывает, что %line% (после того, как set line=%%c соответствует ПОЛНОМУ ПУТИ (хотя я намерен рекурсивно добраться до имени файла, мне все еще нужно добавить условие при поиске строки "\" в %%c, когда ее больше нет, это будет означать, что мы добрались до последнего шага, т.е. %root% теперь будет соответствовать последней корневой папке).

Спасибо, кто попытается помочь мне решить эту проблему.

Обновлено: эта основная программа называется следующим образом:

программа арг1 арг2 арг3 арг4 арг5

arg5 — это путь к файлу, который будет внутренним аргументом для этой другой программы. Чтобы быть как можно более общим, я хочу сделать эту программу функциональной независимо от того, откуда вы ее вызываете. Тем не менее у вас есть два варианта:

  • вы уже находитесь в папке, содержащей файл, который будет обрабатываться этой программой с внутренним вызовом, в таком случае arg5 будет передан как имя файла.dat (без кавычек, за исключением случаев, когда он содержит пробелы)

  • вы не находитесь в корневой папке, поэтому вы передаете непосредственно ПОЛНЫЙ ПУТЬ (в двойных кавычках, если он содержит пробелы).

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

Вот почему я задал этот вопрос. %var% — это просто arg5, как я объяснил здесь.

Надеюсь, я выразился немного яснее, чем раньше.

PS. Я не во всех смыслах опытный программист, поэтому прошу прощения, если ошибаюсь в чистоте и профессионализме. Запись/чтение из/в папку %temp% предназначалась только для использования нового способа пакетного программирования, и ничего больше. Я знал, что это лишнее.

Кстати. Вам не хватает exit /b после основного кода и функции :processtoken.

jeb 22.12.2020 12:39

Хотя вы можете получить некоторые ответы на основе того, что вы опубликовали, я бы не хотел советовать методологию, не понимая точно, что такое %var%. Я думаю, вы действительно должны рассказать нам, как и где он определен, что он может содержать (содержание символов и размер), и как и что именно вы используете для «вызова основного .bat» и любые аргументы к нему ). Существует кнопка редактировать, которую вы можете использовать, чтобы обновить свой вопрос, чтобы включить такую ​​информацию.

Compo 22.12.2020 15:14
set line=%%c работает, а echo Now line writes %line% не работает из-за отсутствия расширения отложенной переменной (в качестве альтернативы можно попробовать call echo Now line writes %%line%% или просто set line). В любом случае, следует избегать разрешения путей с помощью манипуляций со строками, потому что это чревато ошибками…
aschipfl 22.12.2020 15:49

@jeb код - это просто выдержка, конечно, у меня есть выход /b в разделе :end :)

mEm 22.12.2020 16:02

@Compo, спасибо за ответ. %var% — это строка пути, которую я передаю в качестве 5-го аргумента в основной программе. То есть set var=%5 if "%var%"= = "" ( echo [ERROR] 6th input. Please specify an input .dat file! goto :error ) где %5 передается как "C:\fold1\fold2\...\foldN\filename-dat" в строке cmd

mEm 22.12.2020 16:04

@aschipfl попробовал ваше решение и сработал! Спасибо. Что тогда посоветуете??

mEm 22.12.2020 16:22

Нам нужно точно знать, как вводится эта командная строка при передаче через строку cmd. Это очень важно, потому что переменная определяется только после того, как она получена через процесс, который сам может изменить эту строку. Если он всегда заключен в двойные кавычки, всегда будет содержать полный абсолютный путь и не может содержать проблемных символов, у вас уже должна быть необходимая информация. например %~nx5 будет именем файла и расширением, а %~dp5 будет буквой диска и путем (с косой чертой в конце). Set "file=%~nx5" и Set "root=%~dp5"

Compo 22.12.2020 16:25

Что ж, уже есть ответ, который позволяет избежать манипуляций со строками — он вам не помогает? И вы должны следовать совету Compo редактировать свой вопрос (вместо предоставления дополнительной информации, разбросанной по нескольким комментариям)…

aschipfl 22.12.2020 16:26

ЕСЛИ переменная var представляет собой не что иное, как путь к файлу, нет причин записывать ее в файл, а затем считывать обратно с помощью команды FOR. И если вы удаляете окружающие кавычки с помощью команды SET, для этого также нет причин, потому что команда FOR и аргументы командной строки также могут это сделать. Ваш вопрос в представленном виде не соответствует требованиям к минимальному воспроизводимому примеру, поскольку вы не указали, как присваивается переменная VAR.

Squashman 22.12.2020 17:18

@Squashman Я внес правку, надеюсь, это решит некоторые предыдущие недоразумения. Если нет, пожалуйста, скажите мне.

mEm 24.12.2020 15:05
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
10
1 440
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Вы должны взглянуть на модификаторы for-variable (FOR /?)

root=%%~dpz используется для расширения до: d=диск и p=путь к z
file=%%~nxz используется для расширения до: n=имя и x=расширение z

Затем вы можете изменить свой блок на

for /f "tokens=1,* delims= " %%z in (%temp%\filepath.txt) do (
    set "line=%%z"
    set "root=%%~dpz"
    set "file=%%~nxz"
    REM ** Show the variables
    set root
    set file
)

какие-либо преимущества5 для 1,* vs 1*, о которых мне следует знать, или это просто вопрос личных предпочтений? (Я спрашиваю только потому, что предпочитаю отсутствие ленивых персонажей, и, хотя лично для меня это никогда не было проблемой, я мог видеть, что в этом есть какая-то скрытая ошибка)

Ben Personick 22.12.2020 15:53

@BenPersonick Я так не думаю, это просто два способа выразить одно и то же

mEm 22.12.2020 16:18

@jeb, как вы говорите, если %%z читает напрямую весь путь к файлу (root\имя файла), установка root=%%~dpz и file=%%~nxz автоматически сохраняет проблему ??

mEm 22.12.2020 16:20

@micesp да, это было моим предположением в течение 20 лет, но Джеб писал сценарии cmd как минимум в два раза больше, и всегда есть причуды и недокументированные функции / поведение, которые все приносят друг другу.

Ben Personick 22.12.2020 16:23

@BenPersonick с последним комментарием, вы имеете в виду разницу между 1* и 1,* или другим? Я сбит с толку, так как вы упомянули Джеба в своем комментарии.

mEm 22.12.2020 16:36

@MicEsp, только потому, что ты не ответил на мой комментарий под своим основным вопросом, я подумал, что упомяну об этом здесь. Причина в том, что он использует те же методы, что и в ответе выше, но не требует, чтобы вам нужен цикл for или что-то в этом роде, всего две короткие строки кода, Set "file=%~nx5" и Set "root=%~dp5", и все, что необходимы, чтобы делать то, что вам нужно.

Compo 22.12.2020 17:14

@BenPersonick Спасибо, но в данном случае я просто копирую исходный фрагмент кода, не задумываясь :-)

jeb 06.01.2021 16:35

Спасибо, я подумал, что это наиболее вероятно, но решил проверить и посмотреть, есть ли что-то еще :) Хорошего дня :)

Ben Personick 06.01.2021 20:46

Другой способ сделать это в пакетном файле — использовать команду PowerShell Split-Path, предназначенную для этого.

SET "THEFILE=%TEMP%\file path.txt"
FOR /F "delims = " %%A IN ('powershell -NoLogo -NoProfile -Command
    """$([Convert]::ToChar(34))$(Split-Path -Path """%THEFILE%""")$([Convert]::ToChar(34)) $([Convert]::ToChar(34))$(Split-Path -Path """%THEFILE%""" -Leaf)$([Convert]::ToChar(34))"""') DO (
    SET "FILESTRING=%%A"
)

SET "PATHPART = "
FOR %%A IN (%FILESTRING%) DO (
    IF NOT DEFINED PATHPART (SET "PATHPART=%%~A") ELSE (SET "FILEPART=%%~A")
)
ECHO PATHPART is "%PATHPART%"
ECHO FILEPART is "%FILEPART%"

Конечно, проще, если скрипт написан для PowerShell.

$TheFile = "$Env:TEMP\filepath.txt"
$PathPart = Split-Path -Path $TheFile
$FilePart = Split-Path -Path $TheFile -Leaf

ОБНОВЛЯТЬ:

На самом деле, похоже, что для использования PUSHD разбиение пути не требуется. Просто добавьте \.. в конец.

PUSHD C:\Users\joe\afile.txt\..

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

Compo 22.12.2020 19:52

так как вы упомянули set var=%5 в комментарии:

set "root=%~dp5"
set "file=%~nx5"

должно быть все, что вам нужно. Смотрите call /? для более подробной информации.

Я предлагал именно этот код в двух отдельных комментариях за последние несколько часов, но без ответа @Stephan. Возможно, ОП принял ответ и поэтому больше ничего читать не собирается!

Compo 22.12.2020 19:47

@Compo: возможно, вы правы, но это не должно мешать нам давать ответы будущим искателям. ОП должен принять ответ, который помог им (большинству). Со временем голоса покажут воспринимаемую ценность ответов.

Stephan 22.12.2020 20:03

Кстати, Стефан, вы также можете заметить, что я не просто так спросил, что может содержать этот аргумент. Если пятый аргумент может содержать путь к файлу без диска или имя файла без диска или пути, то %~dp5, вероятно, вместо этого будет распространяться с текущим диском и каталогом. Это и тот факт, что даже @aschipfl напомнил ОП обновить свой вопрос необходимой информацией, поэтому я оставил свои ответы в виде комментариев, а не официального ответа. У нас недостаточно информации, чтобы предложить наиболее подходящий код или методологию для задачи.

Compo 22.12.2020 20:16

Другие вопросы по теме