web-dev-qa-db-ja.com

フォルダ文字列をループして、最後のフォルダ名を解析します

現在実行中のバッチファイルのフォルダ名を取得する必要があります。私は次の構文を使用して現在のディレクトリをループしようとしています(これは現在間違っています):

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

'mydir'変数値を検索文字列として渡せないように見えるといういくつかの問題。コマンドを渡した場合にのみ機能するようです。構文が間違っているので、理由がわかりません。

私の考えは、「\」区切り文字を使用してフォルダー文字列をループすることでしたが、これも問題を引き起こしています。各ループに変数を設定すると、最後に設定された値が現在のフォルダー名になります。たとえば、次のパスがあるとします。

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

値 'Folder3'を解析することを期待します。

その名前はバッチファイルのさらに下に作成する別のフォルダーの一部になるため、その値を解析する必要があります。

誰かが助けることができればどうもありがとう。私は間違った木を完全に吠えているかもしれないので、他のアプローチも大いに受け入れられるでしょう。

15
Tim Peel

あなたはそれにかなり近かった:)これはうまくいくはずです:

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

10
Patrick Cuff

これらの提案のいくつかに苦労した後、私は次の1つのライナーが正常に使用されていることを発見しました(Windows 2008で)

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

現在のディレクトリの最後のセグメントを探していたときに、この古いスレッドを見つけました。以前の作家の答えは私を次のように導きます:

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

前に説明したように、%_ LAST_SEGMENT_%で作成されたパスを引用符で囲むことを忘れないでください(私の例で%CD%を使用した場合と同じです)。

これが誰かを助けることを願っています...

6
Paul Margetts

この質問は少し古いですが、私は何度も解決策を探したので、これが私がまとめたばかりのまったく新しい考え方です。

秘訣は、目的のパスをたどり、1レベルバックアップして置換用のフォルダーマスクを作成してから、フォルダーマスクを何も置き換えないことです。

テストするには、任意のディレクトリのコマンドスクリプト(.cmd)にコピーして貼り付け、実行します。それはあなたが現在いる最も深いディレクトリだけを吐き出します。

ノート:

  • %〜dp0を任意のパスに置き換えます(そのままでは、バッチファイルが実行される最も深いフォルダーが返されます。これは%cd%と同じではありません)。
  • 'pathtofind'変数を指定するときは、引用符がないことを確認してください。 「c:\ somepath」ではなくc:\ somepath。
  • フォルダマスキングの元のアイデアは私のものです
  • パス内のスペースは問題ありません
  • フォルダーの深さは問題ではありません
  • これは、このバッチスクリプトのヒントの天才によって可能になりました 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
4
John Dove

3行のスクリプトで結果が得られます...

目標を達成するための2つの追加の方法が見つかりました。この質問に対する他の回答とは異なり、バッチの「関数」や遅延拡張は必要ありません。また、TimPeelの回答のディレクトリの深さに関する制限もありません。

@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
2
djangofan

元のポスターの問題に戻るには:

たとえば、次のパスがあるとします。C:\ Folder1\Folder2\Folder3\Archive.bat値 'Folder3'を解析することを期待します。

そのための簡単な解決策は次のとおりです。

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

'Folder3'を与えます。ファイル/パスが存在する必要はありません。もちろん、....親の親ディレクトリの場合、または......その上のディレクトリの場合(など)も機能します。

2
foo2

@ Jonathan で指定された answer を変更しました。これは、バッチファイルでは機能しなかったためですが、以下では機能し、スペースを含むフォルダーもサポートしています。

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

これは現在のディレクトリを取得し、フォルダが次の場合、以下の例のように最後の最も深いフォルダをエコーし​​ます。

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

バッチコードはこれをエコーし​​ます:デスクトップ環境

1
Super_PDX

シーシュみんな、なんてめちゃくちゃ。これは非常に簡単で、CDなしのメモリでこれを行う方が高速です。

これにより、パスの最後の2つのディレクトリが取得されます。必要に応じて変更して、任意の行の最後のトークンを取得します。これに基づいた元のコードは、私自身の目的のためにより複雑です。

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
1
auvixa

フォルダーの名前にスペースが含まれている場合のわずかな変更-操作の前後にスペースを「:」に置き換えます。

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
1
Tim Peel

これは私たちが最終的に持っていたものです(もう少し粗雑で、とても深くなることしかできません:)

@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%
0
Tim Peel

使用しているWindowsのバージョン(win2k3)かどうかはわかりませんが、FORループでは、単一の文字列を反復処理するのに役立つものは何もありません。私の観察(およびFOR /?情報)によると、FORへの入力の各行に対して1回の反復があり、これを変更して行内で反復する方法はありません。特定の行に対して複数のトークンに分割できますが、これはFORループ本体の1回の呼び出しにすぎません。

これらの回答の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
0
ahains

FORコマンドのバッチファイルでは、%whateverの前に%を追加する必要があります(例:%% whatever)。

'echo%〜p0'は、バッチファイルの現在のディレクトリを出力します。

0
kenny