Мне нужно обработать полный путь к файлу, т.е. 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% предназначалась только для использования нового способа пакетного программирования, и ничего больше. Я знал, что это лишнее.
Хотя вы можете получить некоторые ответы на основе того, что вы опубликовали, я бы не хотел советовать методологию, не понимая точно, что такое %var%
. Я думаю, вы действительно должны рассказать нам, как и где он определен, что он может содержать (содержание символов и размер), и как и что именно вы используете для «вызова основного .bat» и любые аргументы к нему ). Существует кнопка редактировать, которую вы можете использовать, чтобы обновить свой вопрос, чтобы включить такую информацию.
set line=%%c
работает, а echo Now line writes %line%
не работает из-за отсутствия расширения отложенной переменной (в качестве альтернативы можно попробовать call echo Now line writes %%line%%
или просто set line
). В любом случае, следует избегать разрешения путей с помощью манипуляций со строками, потому что это чревато ошибками…
@jeb код - это просто выдержка, конечно, у меня есть выход /b в разделе :end :)
@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
@aschipfl попробовал ваше решение и сработал! Спасибо. Что тогда посоветуете??
Нам нужно точно знать, как вводится эта командная строка при передаче через строку cmd. Это очень важно, потому что переменная определяется только после того, как она получена через процесс, который сам может изменить эту строку. Если он всегда заключен в двойные кавычки, всегда будет содержать полный абсолютный путь и не может содержать проблемных символов, у вас уже должна быть необходимая информация. например %~nx5
будет именем файла и расширением, а %~dp5
будет буквой диска и путем (с косой чертой в конце). Set "file=%~nx5"
и Set "root=%~dp5"
Что ж, уже есть ответ, который позволяет избежать манипуляций со строками — он вам не помогает? И вы должны следовать совету Compo редактировать свой вопрос (вместо предоставления дополнительной информации, разбросанной по нескольким комментариям)…
ЕСЛИ переменная var
представляет собой не что иное, как путь к файлу, нет причин записывать ее в файл, а затем считывать обратно с помощью команды FOR
. И если вы удаляете окружающие кавычки с помощью команды SET
, для этого также нет причин, потому что команда FOR
и аргументы командной строки также могут это сделать. Ваш вопрос в представленном виде не соответствует требованиям к минимальному воспроизводимому примеру, поскольку вы не указали, как присваивается переменная VAR
.
@Squashman Я внес правку, надеюсь, это решит некоторые предыдущие недоразумения. Если нет, пожалуйста, скажите мне.
Вы должны взглянуть на модификаторы for-variable (FOR /?
)
root=%%~dpz
используется для расширения до: d=диск и p=путь к zfile=%%~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*
, о которых мне следует знать, или это просто вопрос личных предпочтений? (Я спрашиваю только потому, что предпочитаю отсутствие ленивых персонажей, и, хотя лично для меня это никогда не было проблемой, я мог видеть, что в этом есть какая-то скрытая ошибка)
@BenPersonick Я так не думаю, это просто два способа выразить одно и то же
@jeb, как вы говорите, если %%z читает напрямую весь путь к файлу (root\имя файла), установка root=%%~dpz и file=%%~nxz автоматически сохраняет проблему ??
@micesp да, это было моим предположением в течение 20 лет, но Джеб писал сценарии cmd как минимум в два раза больше, и всегда есть причуды и недокументированные функции / поведение, которые все приносят друг другу.
@BenPersonick с последним комментарием, вы имеете в виду разницу между 1*
и 1,*
или другим? Я сбит с толку, так как вы упомянули Джеба в своем комментарии.
@MicEsp, только потому, что ты не ответил на мой комментарий под своим основным вопросом, я подумал, что упомяну об этом здесь. Причина в том, что он использует те же методы, что и в ответе выше, но не требует, чтобы вам нужен цикл for или что-то в этом роде, всего две короткие строки кода, Set "file=%~nx5"
и Set "root=%~dp5"
, и все, что необходимы, чтобы делать то, что вам нужно.
@BenPersonick Спасибо, но в данном случае я просто копирую исходный фрагмент кода, не задумываясь :-)
Спасибо, я подумал, что это наиболее вероятно, но решил проверить и посмотреть, есть ли что-то еще :) Хорошего дня :)
Другой способ сделать это в пакетном файле — использовать команду 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\..
Просто чтобы вы знали, что вы не должны разбивать само имя файла, вы должны разбивать имя файла, записанное в его содержимое!
так как вы упомянули set var=%5
в комментарии:
set "root=%~dp5"
set "file=%~nx5"
должно быть все, что вам нужно. Смотрите call /?
для более подробной информации.
Я предлагал именно этот код в двух отдельных комментариях за последние несколько часов, но без ответа @Stephan. Возможно, ОП принял ответ и поэтому больше ничего читать не собирается!
@Compo: возможно, вы правы, но это не должно мешать нам давать ответы будущим искателям. ОП должен принять ответ, который помог им (большинству). Со временем голоса покажут воспринимаемую ценность ответов.
Кстати, Стефан, вы также можете заметить, что я не просто так спросил, что может содержать этот аргумент. Если пятый аргумент может содержать путь к файлу без диска или имя файла без диска или пути, то %~dp5
, вероятно, вместо этого будет распространяться с текущим диском и каталогом. Это и тот факт, что даже @aschipfl напомнил ОП обновить свой вопрос необходимой информацией, поэтому я оставил свои ответы в виде комментариев, а не официального ответа. У нас недостаточно информации, чтобы предложить наиболее подходящий код или методологию для задачи.
Кстати. Вам не хватает
exit /b
после основного кода и функции:processtoken
.