如何在批处理中从完整路径中分离文件名?

69

如何在批处理脚本中将文件名从完整路径中分离出来?


2
可能是一个重复的问题:从变量中批量提取路径和文件名 - Gab
6个回答

94
@echo off
Set filename=C:\Documents and Settings\All Users\Desktop\Dostips.cmd
For %%A in ("%filename%") do (
    Set Folder=%%~dpA
    Set Name=%%~nxA
)
echo.Folder is: %Folder%
echo.Name is: %Name%

但这不是我的功劳,这是Google在http://www.dostips.com/forum/viewtopic.php?f=3&t=409上找到的。


1
谢谢!这对我也有用。我正在从一个文件中读取文件夹列表并格式化它们。我使用了这个命令:"for /F "tokens=1 delims=" %%A in (list_of_files.txt) do (" - Mike Q
1
可能展示如何仅获取文件名会更好。(不包括扩展名。) - Vaccano
3
“%~nI”是从DOS的“for -help”输出中直接摘录的内容,它将扩展%I为仅文件名。 - Pete Stensønes
6
为了澄清,d 表示包含驱动器,p 表示包含路径,n 表示包含文件名,x 表示包含扩展名。 - makhdumi

35

从完整路径名中解析文件名(例如,c:\ temp \ my.bat)到任何组件(例如,File.ext)。

单行代码:

For %%A in ("C:\Folder1\Folder2\File.ext") do (echo %%~fA)

你可以将"C:\Folder1\Folder2\File.ext"替换为任何完整路径,并通过在命令提示符下运行"for /?"来找到其他选项,然后将"%%~fA"进行更改。

详细代码

set "filename=C:\Folder1\Folder2\File.ext"
For %%A in ("%filename%") do (
    echo full path: %%~fA
    echo drive: %%~dA
    echo path: %%~pA
    echo file name only: %%~nA
    echo extension only: %%~xA
    echo expanded path with short names: %%~sA
    echo attributes: %%~aA
    echo date and time: %%~tA
    echo size: %%~zA
    echo drive + path: %%~dpA
    echo name.ext: %%~nxA
    echo full path + short name: %%~fsA)

独立批处理脚本
另存为C:\cmd\ParseFn.cmd

C:\cmd添加到您的PATH环境变量中,并使用它来存储所有可重复使用的批处理脚本。

@echo off
@echo ::___________________________________________________________________::
@echo ::                                                                   ::
@echo ::                              ParseFn                              ::
@echo ::                                                                   ::
@echo ::                           Chris Advena                            ::
@echo ::___________________________________________________________________::
@echo.

::
:: Process arguements
::
if "%~1%"=="/?" goto help
if "%~1%"=="" goto help
if "%~2%"=="/?" goto help
if "%~2%"=="" (
    echo !!! Error: ParseFn requires two inputs. !!!
    goto help)

set in=%~1%
set out=%~2%
:: echo "%in:~3,1%"   "%in:~0,1%"
if "%in:~3,1%"=="" (
    if "%in:~0,1%"=="/" (
    set in=%~2%
    set out=%~1%)
)

::
:: Parse filename
::
set "ret="
For %%A in ("%in%") do (
    if "%out%"=="/f" (set ret=%%~fA)
    if "%out%"=="/d" (set ret=%%~dA)
    if "%out%"=="/p" (set ret=%%~pA)
    if "%out%"=="/n" (set ret=%%~nA)
    if "%out%"=="/x" (set ret=%%~xA)
    if "%out%"=="/s" (set ret=%%~sA)
    if "%out%"=="/a" (set ret=%%~aA)
    if "%out%"=="/t" (set ret=%%~tA)
    if "%out%"=="/z" (set ret=%%~zA)
    if "%out%"=="/dp" (set ret=%%~dpA)
    if "%out%"=="/nx" (set ret=%%~nxA)
    if "%out%"=="/fs" (set ret=%%~fsA)
)
echo ParseFn result: %ret%
echo.

goto end
:help
@echo off
:: @echo ::___________________________________________________________________::
:: @echo ::                                                                   ::
:: @echo ::                           ParseFn Help                            ::
:: @echo ::                                                                   ::
:: @echo ::                           Chris Advena                            ::
:: @echo ::___________________________________________________________________::
@echo.
@echo ParseFn parses a fully qualified path name (e.g., c:\temp\my.bat)
@echo into the requested component, such as drive, path, filename, 
@echo extenstion, etc.
@echo.
@echo Syntax: /switch filename
@echo where,
@echo   filename is a fully qualified path name including drive, 
@echo   folder(s), file name, and extension
@echo.
@echo   Select only one switch:
@echo       /f - fully qualified path name
@echo       /d - drive letter only
@echo       /p - path only
@echo       /n - file name only
@echo       /x - extension only
@echo       /s - expanded path contains short names only
@echo       /a - attributes of file
@echo       /t - date/time of file
@echo       /z - size of file
@echo      /dp - drive + path
@echo      /nx - file name + extension
@echo      /fs - full path + short name
@echo.

:end
:: @echo ::___________________________________________________________________::
:: @echo ::                                                                   ::
:: @echo ::                         ParseFn finished                          ::
:: @echo ::___________________________________________________________________::
:: @echo.

“Elaborated code” 可能存在错误;d 不是目录条目?或者在批处理文件中产生不同的效果?正如“独立批处理脚本”所示? - user3082

7
@echo off
Set filename="C:\Documents and Settings\All Users\Desktop\Dostips.cmd"
call :expand %filename%
:expand
set filename=%~nx1
echo The name of the file is %filename%
set folder=%~dp1
echo It's path is %folder%

当我运行这个程序时,它会输出两次相同的行。我不确定如何解决这个问题。以下是输出内容:文件名为Dostips.cmd,路径为C:\Documents and Settings\All Users\Desktop\ 文件名为,路径为 - Ste
只有在路径不存在时才会发生这种情况。有没有不使用if语句的解决方法?但是这是一个很好的解决方案,谢谢。 - Ste
不,那也不是。如果我在代码底部添加 echo anther line,它的行为也是一样的。 - Ste

1

继续Pete上面的例子,要在cmd窗口中直接执行,使用单个%,例如:

cd c:\test\folder A
for %X in (*)do echo %~nxX

(注意,像desktop.ini这样的特殊文件不会显示。)

还可以使用>>将输出重定向到文件中:

cd c:\test\folder A
for %X in (*)do echo %~nxX>>c:\test\output.txt

对于一个真实的例子,假设你想从文件夹A复制所有文件到文件夹B(非递归):

cd c:\test\folder A
for %X in (*)do robocopy . "c:\test\folder B" "%~nxX" /dcopy:dat /copyall /v>>c:\test\output.txt

以及所有文件夹(递归):

cd c:\test\folder A
对于每个文件夹X,使用robocopy命令将其复制到"C:\ test \ folder B \%X"中,使用/e /copyall /dcopy:dat选项,并将输出写入c:\ test \ output2.txt。

在使用这个工具时,我发现如果你将这些技巧与robocopy一起使用,你还需要记得删除源目录中的最后一个反斜杠。如果有一个使用%~dpX作为源的示例会很有用。 - AnnanFay

0

我对批处理文件并不是很了解,但你可以从主目录复制一个预先制作好的批处理文件到你所在的路径,然后返回文件名列表,再使用该名称吗?

这里有一个链接,我认为可能会有助于制作预先制作好的批处理文件。

http://www.ericphelps.com/batch/lists/filelist.htm


0

在我需要批处理脚本后,只是想分享我的2美分。使用for根本没有帮助,因为我想要一个字面上的dir和filemask。

即给定c:\dir1\subdir\*.asm,我需要进一步处理的字面上的c:\dir1\subdir*.asm

:parsepathname pathname dirname filename
  @echo OFF
  if "%~3"=="" exit /b -1 ERROR!
  setlocal enableDelayedExpansion
  set "dirname="
  set "filename=%~1"
  set "check=%filename:\=%"
  if "%check%"=="%filename%" goto pfn_Love1Done
  set "ctr=0" & set "pathname=%~1" & set "filename="
  :pfn_Love1
    if ctr LSS -260 exit /b -2 ERROR!
    set /a "ctr-=1"
    set "ch=!pathname:~%ctr%,1!" 
    if not "%ch%"=="\" goto pfn_Love1
    set "dirname=!pathname:~0,%ctr%!"
    set /a "ctr+=1"
    set "filename=!pathname:~%ctr%!"
  :pfn_Love1Done
  rem echo DEBUG: pathname="%pathname%" dirname="%dirname%" filename="%filename%"
  endlocal & set "%~2=%dirname%" & set "%~3=%filename%"
exit /b

call with调用 %pathname% 目录名 文件名,目录名路径名


@(set "%2=%dp0" & set "%3=%nx1") - Stephan
@(set "%2=%dp0" & set "%3=%nx1") - Stephan
不行。正如我所说,我不希望通配符被解释为文件名。我需要字面上的通配符本身,例如通过 for /r dir in (wildcard) 进一步处理。这里提出的所有解决方案,包括你的,都会将 %~nxf 解释为找到的最后一个文件名。而不是通配符本身。这是一个巨大的区别。也许大多数用户不需要我的解决方案,但我只是为那些需要它却不知道如何做的1%用户提供了它。 - user6801759
不。正如我所说的,我不希望通配符被解释为文件名。我需要字面上的通配符本身,例如通过for /r dir in (wildcard)进一步处理。这里提出的所有解决方案,包括你的,都会将%~nxf翻译为找到的最后一个文件名,而不是通配符本身。这是一个巨大的区别。也许大多数用户不需要我的解决方案,我只是为那些需要但不知道如何做的1%用户提供了一个选择。 - user6801759
当然,我的解决方案并不是唯一的。例如,您可以将路径替换为空字符串set filename="%pathname:%~dpf/=%",这在大多数情况下都有效,但仍需要检查路径名是否包含驱动器号或是否有任何目录部分。 - user6801759
抱歉,我误解了您的问题(我的代码只有在没有文件匹配掩码时才能正常工作)。 - Stephan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接