Перебрать строку папки и проанализировать последнее имя папки

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

set mydir = %~p0
for /F "delims=\" %i IN (%mydir%) DO @echo %i

Пара проблем в том, что я не могу передать значение переменной mydir в качестве строки поиска. Кажется, это работает, только если я передаю команды; У меня неправильный синтаксис, и я не могу понять, почему.

Я думал, что нужно зациклить строку папки с разделителем '\', но это тоже вызывает проблемы. Если я установлю переменную в каждом цикле, то последним установленным значением будет имя текущей папки. Например, учитывая следующий путь:

C:\Папка1\Папка2\Папка3\Архив.bat

Я бы ожидал разобрать значение «Папка3».

Мне нужно разобрать это значение, так как его имя будет частью другой папки, которую я собираюсь создать дальше в пакетном файле.

Большое спасибо, если кто-то может помочь. Я могу полностью лаять не на то дерево, поэтому любые другие подходы также будут хорошо приняты.


person Tim Peel    schedule 11.11.2008    source источник


Ответы (13)


Вы были довольно близки к этому :) Это должно работать:

@echo OFF
set mydir="%~p0"
SET mydir=%mydir:\=;%

for /F "tokens=* delims=;" %%i IN (%mydir%) DO call :LAST_FOLDER %%i
goto :EOF

:LAST_FOLDER
if "%1"=="" (
    @echo %LAST%
    goto :EOF
)

set LAST=%1
SHIFT

goto :LAST_FOLDER

По какой-то причине команде for не нравится '\' в качестве разделителя, поэтому я преобразовал все '\' в ';' первый (SET mydir=%mydir:\=;%)

person Patrick Cuff    schedule 11.11.2008
comment
В качестве разделителя ему нравится |, просто нужно заключить %mydir% в кавычки, как в %%i IN ("%mydir%") - person ErikE; 23.11.2010

После борьбы с некоторыми из этих предложений я нашел успешно использованный следующий 1 лайнер (в Windows 2008)

for %%a in (!FullPath!) do set LastFolder=%%~nxa
person Jonathan    schedule 03.01.2011
comment
Это не удалось, если в имени файла есть пробел. Пожалуйста, добавьте двойные кавычки вокруг !FullPath! чтобы это работало - person Rupin; 04.10.2011
comment
Сладкий. Спасибо. Вот как я это использовал: `для /d %%P в (%IndividualProjectsFolder%*) do for %%F in (%%P) do 7z a %TempRootFolder%\ZIPs\CADblokeCADtoolFor%%~nxF.zip %IndividualProjectsFolder%\ %%~nxF` (ошибка уценки) - person CAD bloke; 01.11.2012
comment
На случай, если кто-то еще, как и я, не сразу увидит корреляцию, последний символ переменной %%~nxa должен быть равен используемой переменной FOR. Итак, %%a == %%~nxa, %%g == %%~nxg и т. д. - person mythofechelon; 27.12.2012
comment
Не работает вообще. Я только что получил имя файла и расширение - person user565739; 12.11.2013

Я нашел этот старый поток, когда искал последний сегмент текущего каталога. Предыдущие ответы авторов приводят меня к следующему:

FOR /D %%I IN ("%CD%") DO SET _LAST_SEGMENT_=%%~nxI
ECHO Last segment = "%_LAST_SEGMENT_%"

Как объяснялось ранее, не забудьте заключить в кавычки все пути, созданные с помощью %_LAST_SEGMENT_% (точно так же, как я сделал с %CD% в моем примере).

Надеюсь, это поможет кому-то...

person Paul Margetts    schedule 24.09.2012

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

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

Чтобы проверить это, просто скопируйте и вставьте в командный сценарий (.cmd) в любом каталоге, а затем запустите его. Он выдаст только самый глубокий каталог, в котором вы сейчас находитесь.

Примечания:

  • Замените % ~ dp0 на любой путь, который вам нравится (как есть, он вернет самую глубокую папку, из которой запускается командный файл. Это не то же самое, что % cd %.)
  • При указании переменной pathtofind убедитесь, что нет кавычек, например. c:\some path, а не "c:\some path".
  • Оригинальная идея маскировки папок принадлежит мне.
  • Пробелы в пути не проблема
  • Глубина папки не проблема
  • Это стало возможным благодаря гениальному совету по пакетному скриптингу http://www.dostips.com/DtCodeBatchFiles.php#Batch.FindAndReplace

Надеюсь, это поможет кому-то еще.

@echo off
set pathtofind=%~dp0
if not exist %pathtofind% echo Path does not exist&pause>nul&goto :eof

cd /d %pathtofind%
set path1=%cd%
cd ..
set path2=%cd%

call set "path3=%%path1:%path2%\=%%"

echo %path3%

pause>nul
person John Dove    schedule 04.07.2010

3 строчки скрипта дают результат...

Найдены 2 дополнительных способа достижения цели, и, в отличие от других ответов на этот вопрос, он не требует пакетных «функций», отложенного расширения, а также не имеет ограничения, которое имеет ответ Тима Пила с глубиной каталога:

@echo off
SET CDIR=%~p0
SET CDIR=%CDIR:~1,-1%
SET CDIR=%CDIR:\=,%
SET CDIR=%CDIR: =#%
FOR %%a IN (%CDIR%) DO SET "CNAME=%%a"
ECHO Current directory path: %CDIR%
SET CNAME=%CNAME:#= %
ECHO Current directory name: %CNAME%
pause

ПЕРЕСМОТР: после моей новой версии, вот пример вывода:

Current directory path: Documents#and#Settings,username,.sqldeveloper,tmp,my_folder,MY.again
Current directory name: MY.again
Press any key to continue . . .

Это означает, что скрипт не обрабатывает «#» или «,» в имени папки, но его можно настроить для этого.

ДОПОЛНЕНИЕ. Спросив кого-то на форуме dostips, я нашел еще более простой способ:

@echo off
SET "CDIR=%~dp0"
:: for loop requires removing trailing backslash from %~dp0 output
SET "CDIR=%CDIR:~0,-1%"
FOR %%i IN ("%CDIR%") DO SET "PARENTFOLDERNAME=%%~nxi"
ECHO Parent folder: %PARENTFOLDERNAME%
ECHO Full path: %~dp0
pause>nul
person djangofan    schedule 03.11.2011
comment
Он не использовал отложенное расширение или пакетные функции, но во многих случаях он терпит неудачу, например C:\ , C:\myPath,with,comma, C:\Documents & Settings и C:\myPath_with_underscores. - person jeb; 04.11.2011
comment
Это второстепенные случаи, которые крайне редко встречаются в реальном мире. Проблема с подчеркиванием встречается чаще, и ее легко обойти. Я обновлю свой ответ, чтобы учесть этот. - person djangofan; 04.11.2011
comment
Вы должны использовать синтаксис quotd в своих операторах set, иначе у вас возникнут проблемы со специальными символами, такими как &. Вместо SET CDIR=%~p0 попробуйте SET "CDIR=%~p0" и SET "_CDIR=%CDIR:~1,-1%" - person jeb; 06.11.2011

Чтобы вернуться к проблеме оригинального плаката:

Например, учитывая следующий путь: C:\Folder1\Folder2\Folder3\Archive.bat, я ожидал бы проанализировать значение «Folder3».

Простое решение для этого:

for /D %%I in ("C:\Folder1\Folder2\Folder3\Archive.bat\..") do echo parentdir=%%~nxI

даст «Папка3». Файл/путь не обязательно должен существовать. Конечно, .... для родительского каталога родителя или ...... для того, что выше (и так далее), тоже работает.

person foo2    schedule 10.05.2012

Небольшое изменение, если в именах каких-либо папок есть пробелы - заменить пробел на ':' до и после операции:

set mydir="%~p0"
set mydir=%mydir:\=;%
set mydir=%mydir: =:%

for /F "tokens=* delims=;" %%i IN (%mydir%) DO call :LAST_FOLDER %%i
goto :EOF

:LAST_FOLDER
if "%1"=="" (
  set LAST=%LAST::= %
  goto :EOF
)

set LAST=%1
SHIFT

goto :LAST_FOLDER
person Tim Peel    schedule 11.11.2008
comment
Это не нужно. Просто поместите кавычки вокруг %mydir% в операторе for. - person ErikE; 23.11.2010

Блин, ребята, какой беспорядок. Это довольно просто, и быстрее сделать это в памяти без CD.

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

К вашему сведению, это, вероятно, не позволяет использовать пути с восклицательными знаками, так как я использую enabledelayedexpansion, но это можно исправить.

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

@echo off&setlocal enableextensions,enabledelayedexpansion

call :l_truncpath "C:\Windows\temp"

----------

:l_truncpath
set "_pathtail=%~1"
:l_truncpathloop
for /f "delims=\ tokens=1*" %%x in ("!_pathtail!") do (
if "%%y"=="" (
set "_result=!_path!\!_pathtail!"
echo:!_result!
exit/b
)
set "_path=%%x"
set "_pathtail=%%y"
)
goto l_truncpathloop
person auvixa    schedule 18.10.2010

Я изменил ответ, данный @ Джонатан, так как у меня это не сработало в пакетном файле, но это ниже работает, а также поддерживает папки с пробелами в нем.:

for %%a in ("%CD%") do set LastFolder=%%~nxa
echo %LastFolder%

Это берет текущий каталог и отображает последнюю, самую глубокую папку, как в приведенном ниже примере, если папка следующая:

C:\Users\SuperPDX\OneDrive\Desktop Environment\

Пакетный код повторяет это: Desktop Environment

person Super_PDX    schedule 05.10.2019

В пакетных файлах в команде FOR вам нужно добавить перед %whatever дополнительный % (например, %%whatever).

'echo %~p0' напечатает текущий каталог пакетного файла.

person kenny    schedule 11.11.2008
comment
нет, он печатает весь путь к текущему каталогу за вычетом буквы диска. - person djangofan; 03.11.2011
comment
Я бы никогда не проголосовал, в результате чего ваш ответ получил бы -1. Но, с другой стороны, не будучи тем, чего хотел спрашивающий, ваш ответ тоже не заслуживал 1. - person djangofan; 04.11.2011

Это то, что у нас было в конце (немного более грубый и может только углубляться :)

@echo off
for /f "tokens=1-10 delims=\" %%A in ('echo %~p0') do (
    if NOT .%%A==. set new=%%A
    if NOT .%%B==. set new=%%B
    if NOT .%%C==. set new=%%C
    if NOT .%%D==. set new=%%D
    if NOT .%%E==. set new=%%E
    if NOT .%%F==. set new=%%F
    if NOT .%%G==. set new=%%G
    if NOT .%%H==. set new=%%H
    if NOT .%%I==. set new=%%I
    if NOT .%%J==. set new=%%J
)

@echo %new%
person Tim Peel    schedule 11.11.2008

Я не знаю, является ли это версией Windows, в которой я работаю (win2k3), но цикл FOR не дает мне ничего полезного для попытки перебрать одну строку. Согласно моему наблюдению (и информации FOR /?), вы получаете одну итерацию для каждой строки ввода в FOR, и нет никакого способа изменить это, чтобы итерация выполнялась внутри строки. Вы можете разбить несколько токенов для данной строки, но это только один вызов тела цикла FOR.

Я действительно думаю, что подход CALL:LABEL в этих ответах отлично работает. Что-то, чего я не знал, пока не посмотрел это, было то, что ";" и "," распознаются как разделители аргументов. Поэтому, как только вы замените обратную косую черту точкой с запятой, вы можете вызвать свою метку и выполнить итерацию с помощью SHIFT.

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

@echo off
if "%1"=="" goto :USAGE

set FULLPATH=%~f1
set STOPDIR=%2
set PATHROOT=

:: Replace backslashes with semicolons
set FULLPATH=%FULLPATH:\=;%

:: Iterate through path (the semicolons cause each dir name to be a new argument)
call :LOOP %FULLPATH%
goto :EOF

:LOOP

::Exit loop if reached the end of the path, or the stop dir
if "%1"=="" (goto :EOF)
if "%1"=="%STOPDIR%" (goto :EOF)

::If this is the first segment of the path, set value directly. Else append.
if not defined PATHROOT (set PATHROOT=%1) else (set PATHROOT=%PATHROOT%\%1)

::shift the arguments - the next path segment becomes %i
SHIFT

goto :LOOP

:USAGE
echo Usage:
echo %~0 ^<full path to parse^> ^<dir name to stop at^>
echo E.g. for a command:
echo %~0 c:\root1\child1\child2 child2
echo The value of c:\root1\child1 would be assigned to env variable PATHROOT
person ahains    schedule 11.06.2010

К сожалению, это прекрасно работает только при некоторой глубине, но есть проблемы с нахождением на самой вершине горы... Помещение этой программы в "C:\Windows", например. в результате получится... "C:\Windows", а не ожидаемая "Windows". Все еще отличная работа, и все еще повреждения могут быть устранены. Мой подход:

@echo off
set pathtofind=%~dp0
if not exist %pathtofind% echo Path does not exist&pause>nul&goto :eof

cd /d %pathtofind%
set path1=%cd%
cd ..
set path2=%cd%
set path4=%~dp1
call set "path3=%%path1:%path2%\=%%"
call set "path5=%%path3:%path4%*\=%%"
echo %path5%

pause>nul

И у меня это работает просто отлично, спасибо за идею, я искал что-то подобное в течение некоторого времени.

person jeth    schedule 23.08.2010
comment
Ну и копировать ответы других людей немного безвкусно. - person ErikE; 23.11.2010