一个Windows批处理文件能否确定自己的文件名?

162

一个 Windows 批处理文件能否确定自己的文件名?

例如,如果我运行批处理文件 C:\Temp\myScript.bat,是否有一条命令可以在 myScript.bat 文件中确定字符串 "myScript.bat"?


2
%0 就是你要找的。请参阅此问题获取更多信息。 - Jonathon Reinhart
2
是的,那就是我要找的。%~nx0就是答案。 - djangofan
6个回答

217

可以。

使用特殊变量%0获取当前文件的路径。

写入%~n0以仅获取不带扩展名的文件名。

写入%~n0%~x0以获取文件名和扩展名。

也可以写%~nx0以获取文件名和扩展名。


2
这只是不准确的。%0和%~n0都只获取文件名部分。@djangofan的答案是正确的。 - JustJeff
10
%0 返回文件调用的方式。如果使用了完整路径,%0 将有该路径。如果你先进入目录并从那里执行批处理,则 %0 通常不包含路径信息(但在这种情况下,你可以从 %cd% 获取该信息)。 - Gogowitsch
@gogowitsch:你确定吗?我不认为那是真的。 - SLaks
1
在 Win2012 上,%cd% 将返回调用批处理文件的进程的当前目录。因此,如果您在 D:\ dir1 提示符处,并输入 Y:\ foo\bar.bat,如果 bar.bat 具有 @echo % cd%,则将输出 D:\ dir1 - Preacher

62

您可以获取文件名,但是也可以获取完整路径,具体取决于您在“%~”和“0”之间放置的内容。从以下选项中选择:

d -- drive
p -- path
n -- file name
x -- extension
f -- full path

比如,从c:\tmp\foo.bat内部,%~nx0会给你"foo.bat",而%~dpnx0会给你"c:\tmp\foo.bat"。请注意,这些片段总是按照规范顺序组装的,因此如果你聪明地尝试%~xnpd0,你仍然会得到"c:\tmp\foo.bat"。


4
在你的代码块里,你声明 f 是文件名,但在你的例子中你用了 n 作为文件名。经过一些测试,似乎 f 是完整路径,而 n 是文件名。 - Drew Chapin
@druciferre,我根据您的评论编辑了答案。 - robotik
如果你想聪明地尝试%~xnpd0...我爱你。 - Mark Deven

37

使用以下基于SLaks的回答的脚本,我确定正确答案是:

echo The name of this file is: %~n0%~x0
echo The name of this file is: %~nx0

这是我的测试脚本:

@echo off
echo %0
echo %~0
echo %n0
echo %x0
echo %~n0
echo %dp0
echo %~dp0
pause

我觉得有趣的是,我们知道波浪线字符通常用于去掉变量的引号/修剪引号,但%nx0却不起作用。


18
请牢记,在批处理文件中,参数号码的0是一种特殊情况,其中0表示命令行上给出的此文件
因此,如果文件名为myfile.bat,则您可以按以下几种方式调用它,每种方式都会从%0%~0使用中给出不同的输出: myfile myfile.bat mydir\myfile.bat c:\mydir\myfile.bat "c:\mydir\myfile.bat" 如果您从该文件所在目录的正确相对位置调用它,则以上所有调用都是合法的。 %~0会从最后一个示例中去掉引号,而%0则不会。
由于这些都会产生不同的结果,%0%~0很可能不是您想要使用的内容。
以下是一个批处理文件的示例:
@echo Full path and filename: %~f0
@echo Drive: %~d0
@echo Path: %~p0
@echo Drive and path: %~dp0
@echo Filename without extension: %~n0
@echo Filename with    extension: %~nx0
@echo Extension: %~x0
@echo Filename as given on command line: %0
@echo Filename as given on command line minus quotes: %~0
@REM Build from parts
@SETLOCAL
@SET drv=%~d0
@SET pth=%~p0
@SET fpath=%~dp0
@SET fname=%~n0
@SET ext=%~x0
@echo Simply Constructed name: %fpath%%fname%%ext%
@echo Fully  Constructed name: %drv%%pth%%fname%%ext%
@ENDLOCAL
pause

3
尝试运行以下代码示例,以感受神奇变量的工作方式。
@echo off

SETLOCAL EnableDelayedExpansion

echo Full path and filename: %~f0
echo Drive: %~d0
echo Path: %~p0
echo Drive and path: %~dp0
echo Filename without extension: %~n0
echo Filename with    extension: %~nx0
echo Extension: %~x0

echo date time : %~t0
echo file size: %~z0

ENDLOCAL

相关规则如下。
%~I         - expands %I removing any surrounding quotes ("")
%~fI        - expands %I to a fully qualified path name
%~dI        - expands %I to a drive letter only
%~pI        - expands %I to a path only
%~nI        - expands %I to a file name only
%~xI        - expands %I to a file extension only
%~sI        - expanded path contains short names only
%~aI        - expands %I to file attributes of file
%~tI        - expands %I to date/time of file
%~zI        - expands %I to size of file
%~$PATH:I   - searches the directories listed in the PATH
               environment variable and expands %I to the
               fully qualified name of the first one found.
               If the environment variable name is not
               defined or the file is not found by the
               search, then this modifier expands to the
               empty string

0
以下是我的初始代码:
@echo off
Set z=%%
echo.
echo %z%0.......%0
echo %z%~0......%~0
echo %z%n0......%n0
echo %z%x0......%x0
echo %z%~n0.....%~n0
echo %z%dp0.....%dp0
echo %z%~dp0....%~dp0
echo.

我注意到%~0和%0给出的文件名是在命令行中输入的方式,而不是文件实际命名的方式。因此,如果您想要使用文件名的字面大小写,您应该使用%~n0。但是,这将省略文件扩展名。但是,如果您知道文件名,您可以添加以下代码。
set b=%~0
echo %~n0%b:~8,4%

我了解到“:〜8,4%”的意思是从变量的第9个字符开始显示接下来的4个字符。范围是从0到变量字符串的结尾。所以%Path%会非常长!

fIlEnAmE.bat
012345678901

然而,这并不像Jool的解决方案(%~x0)那样可靠。

我的证据:

C:\bin>filename.bat

%0.......filename.bat
%~0......filename.bat
. . .

C:\bin>fIlEnAmE.bat

%0.......fIlEnAmE.bat
%~0......fIlEnAmE.bat
%n0......n0
%x0......x0
%~n0.....FileName
%dp0.....dp0
%~dp0....C:\bin\

%~n0%b:~8,4%...FileName.bat

Press any key to continue . . .

C:\bin>dir
 Volume in drive C has no label.
 Volume Serial Number is CE18-5BD0

 Directory of C:\bin
. . .
05/02/2018  11:22 PM               208 FileName.bat

以下是最终代码

@echo off
Set z=%%
set b=%~0
echo.
echo %z%0.......%0
echo %z%~0......%~0
echo %z%n0......%n0
echo %z%x0......%x0
echo %z%~n0.....%~n0
echo %z%dp0.....%dp0
echo %z%~dp0....%~dp0
echo.
echo A complex solution:
echo ===================================
echo %z%~n0%z%b:~8,4%z%...%~n0%b:~8,4%
echo ===================================
echo.
echo The preferred solution:
echo ===================================
echo %z%~n0%z%~x0.......%~n0%~x0
echo ===================================
pause

我可能漏掉了什么,但对我来说,您的最终脚本示例的复杂解决方案对我无效。至少如果脚本命名为“ScriptPathTest.cmd”则不起作用。如果您执行“set b =%〜snx0”,那么它将被设置为“SCRIPT〜1.cmd”,然后您可以像往常一样取最后四个字符,但此时您也可以只是执行set b =%〜x0并使用%b%或...就像在首选项中所做的那样,只需使用%〜x0。= P - Brent Rittenhouse
还应该注意到,在调用的函数内部,%0是无法工作的,因此我喜欢将我的脚本起始设置为:@( echo off & setlocal EnableDelayedExpansion & set previous_errorlevel=%ERRORLEVEL% & set script_name=%~0 & ( call :run %* || goto :exit_failure ) & goto :exit_success ) .. 实际上,&s表示换行符。对于那些想知道的人,我会存储先前的错误级别,以防用户使用/?,-h,--h,-help或--help调用脚本,这样我就不会为他们不必要地覆盖它。 - Brent Rittenhouse
哦,看起来 %0 或 %0 没有字母会输出子程序的名称,但如果你使用 %n0,%x0,%nx0,%~f0 等等,则会输出脚本名称的相应部分。所以你要么事先存储它,要么确保始终使用字母。 - Brent Rittenhouse

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