Зацикливать строку папки и анализировать имя последней папки

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

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

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

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

C:\Folder1\Folder2\Folder3\Archive.bat

Я ожидал бы разобрать значение 'Folder3'.

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

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

Ответы

Ответ 1

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

@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:\=;%)

Ответ 2

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

for %%a in (!FullPath!) do set LastFolder=%%~nxa

Ответ 3

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

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

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

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

Ответ 4

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

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

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

Примечания:

  • Замените% ~ dp0 любым нужным вам путем (так как он вернет самую глубокую папку, из которой запускается командный файл. Это не то же самое, что% cd%.)
  • При указании переменной pathtofind убедитесь, что нет кавычек, например, c:\некоторый путь, а не "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

Ответ 5

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

Найден 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

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

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

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

ДОБАВЛЕНИЕ: после того, как кто-то спросил в 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

Ответ 6

Чтобы вернуться к исходной версии плаката:

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

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

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

предоставит 'Folder3'. Файл/путь не должен существовать. Конечно,.... для родительского родительского каталога, или...... для одного выше, что (и т.д.) Тоже работают.

Ответ 7

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

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

Ответ 8

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

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

Fyi, это, вероятно, не допускает путей с восклицательными знаками, поскольку я использую 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

Ответ 9

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

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

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

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

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

Ответ 10

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

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

Ответ 11

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

@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%

Ответ 12

Я не знаю, является ли это версией окон, на которых я включен (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

Ответ 13

К сожалению, это прекрасно работает только тогда, когда находится на некоторой глубине, но есть проблемы с нахождением на самой вершине горы... Поместить эту программу в "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

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