Зацикливать строку папки и анализировать имя последней папки - PullRequest
15 голосов
/ 11 ноября 2008

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

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

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

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

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

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

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

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

Ответы [ 12 ]

19 голосов
/ 03 января 2011

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

for %%a in (!FullPath!) do set LastFolder=%%~nxa
10 голосов
/ 11 ноября 2008

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

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

6 голосов
/ 24 сентября 2012

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

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

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

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

4 голосов
/ 05 июля 2010

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

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

Чтобы проверить это, просто скопируйте и вставьте в командный скрипт (.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
2 голосов
/ 10 мая 2012

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

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

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

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

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

2 голосов
/ 03 ноября 2011

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 . . .

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

ADDENDUM: Спросив кого-то на форуме 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
1 голос
/ 19 октября 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
1 голос
/ 11 ноября 2008

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

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
0 голосов
/ 23 августа 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

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

0 голосов
/ 11 июня 2010

Я не знаю, включена ли это версия окон (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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...