批处理:删除文件扩展名

196

我有以下来自维基百科的批处理脚本:

@echo off
    for /R "C:\Users\Admin\Ordner" %%f in (*.flv) do (
    echo %%f
)
pause

在for循环中,所有扩展名为flv的文件都会被回显出来, 但我想对文件执行一些操作, 需要一次使用没有扩展名的文件和一次使用有扩展名的文件。 我该如何得到这两个文件呢?

我搜索了解决方案,但没有找到。 我是批处理的新手...

7个回答

383

您可以使用 %%~nf,如for的参考中所述,仅获取文件名:

@echo off
    for /R "C:\Users\Admin\Ordner" %%f in (*.flv) do (
    echo %%~nf
)
pause
以下选项可用:
变量及其修饰符         描述
%~I 展开 %I,移除任何的引号(")。 %~fI 展开 %I,获得完整限定路径名。 %~dI 展开 %I,仅获得磁盘驱动器字母。 %~pI 展开 %I,仅获得路径。 %~nI 展开 %I,仅获得文件名。 %~xI 展开 %I,仅获得文件扩展名。 %~sI 展开路径,仅包含短名称。 %~aI 展开 %I,获得文件的属性。 %~tI 展开 %I,获得文件的日期和时间。 %~zI 展开 %I,获得文件的大小。 %~$PATH:I 在 PATH 环境变量列出的目录中搜索并展开 %I,获得找到的第一个完全合格的文件名。如果未定义环境变量名称或未通过搜索找到文件,则该修改符扩展为空字符串。

16
简短说明:在上述示例中,**%%f** 将类似于 C:\Users\Admin\Ordner\foo.flv,而 %%~nf 将给出 foo。如果您想获得除扩展名之外的所有内容,请使用 %%df%%pf%%~nf,这将给您 C:\Users\Admin\Ordner\foo - ehambright
16
晚了点评论,但我认为使用 %%~dpnf 可以是更短的替代方案。 - user6250760
1
感谢Dirk提供的修改器/描述表。我的情况是在批处理脚本中从参数%1获取不带扩展名的文件名。echo %~n1正是我想要的。 - Dave Pile

40

如果您的变量中包含的文件实际上不存在,则FOR方法将无法工作。 如果您知道扩展名的长度,可以使用一个技巧,即截取子字符串:

在这种情况下,如果你的变量中所代表的文件不存在,FOR方法就不会起作用。 一种技巧是,如果你知道文件扩展名的长度,那么可以截取子字符串:

%var:~0,-4%

-4表示最后4位数字(可能是.ext)将被截断。


1
这对我不起作用(在Win8.1上) - 也许当我在问题中使用的示例环境中尝试 echo %f:~0,-4% 时我误解了它。 我做错了什么? - Wolf
3
显然,这适用于“普通”变量,而不是FOR变量(或者可能是我不知道正确的语法)。无论如何,这在OP示例的上下文中有效:SET fl=%%f,然后echo %fl:~0,-4% - Ohad Schneider
@Wolf 你需要将循环变量的值设置为普通变量,然后在普通变量中进行字符串替换/截断。 - phuclv
在很多情况下,扩展名长度不等于3或者是未知的。即使文件不存在,你仍然可以使用for语句,详见我的回答。 - marsze

15

不使用循环

如果我只想从文件名或变量中去掉扩展名(而不列出任何目录或现有文件),我会使用这个:

for %%f in ("%filename%") do set filename=%%~nf

如果您想从完整路径中删除扩展名,请改用%%dpnf

for %%f in ("%path%") do set path=%%~dpnf

示例:

(可直接在控制台中使用)

@for %f in ("file name.dat") do @echo %~nf
@for %f in ("C:\Dir\file.dat") do @echo %~dpnf

OUTPUT:

file name
C:\Dir\file

14

我对Windows的命令行也不太熟悉,但可以试试这个方法:

echo %%~nf

10
如果你的变量是一个参数,你可以简单地使用%~dpn(对于路径)或%~n(仅包含名称),后面跟着参数编号,这样你就不用担心扩展名长度的变化。
例如%~dpn0将返回批处理文件的路径而不包含其扩展名,%~dpn1将为%1,不包含扩展名,以此类推。
%~n0将返回批处理文件的名称而不带有其扩展名,%~n1将为%1,不包含路径和扩展名,以此类推。
完整的内容是%~dpfn0,当你仔细看时它开始变得有意义:
  • d是驱动器
  • p是路径
  • n是名称
  • x是扩展名,
  • fn是带有扩展名的文件名

谢谢!%~dpn 保留了整个文件路径,但不包括扩展名,而 %~nf 则以某种方式保留了扩展名。 - Guillaume F.
@GuillaumeF。是的,谢谢你指出这一点。我更新了我的答案,以便更深入地解释这些字母。 - Martin Braun
"f" 是文件名,"x" 是扩展名。 - Mud
+1 表示这些字母的含义。我不喜欢批处理(但还是会用),所以通常会复制/粘贴这些字母,而不会太在意它们的含义。现在,我知道了 :) - akinuri

9
这是一份相当晚的回复,但我想到了一个解决方案来解决我在DiskInternals LinuxReader中遇到的问题。该软件将保存到非NTFS(FAT32)目录的文件附加了“.efs_ntfs”后缀。
@echo off
REM %1 is the directory to recurse through and %2 is the file extension to remove
for /R "%1" %%f in (*.%2) do (
    REM Path (sans drive) is given by %%~pf ; drive is given by %%~df
    REM file name (sans ext) is given by %%~nf ; to 'rename' files, move them
    copy "%%~df%%~pf%%~nf.%2" "%%~df%%~pf%%~nf"
    echo "%%~df%%~pf%%~nf.%2" copied to "%%~df%%~pf%%~nf"
echo.
)
pause

我不确定它是否回答了所问的问题,但它确实帮助了我,谢谢! - matan7890
1
@matan7890 是的;op没有明确说明“我想对文件执行一些操作”的具体内容,但其中一个操作可能是重命名它们,在这种情况下,我的答案是已接受答案的扩展。 - Agi Hammerthief
这对我的一个朋友有所帮助,他打开了一个附件后发现他的所有文件都被添加了“.encrypted”后缀,并附带了勒索要求。显然,攻击脚本必须是一个批处理文件,其作用是将所有文件添加“.encrypted”后缀。 - AwokeKnowing
1
因为您提到了驱动器、路径和扩展名(**%%df%%pf%%nf),这与原问题中的%%f输出最相似,而不仅仅是没有扩展名的文件名(%%nf**),所以我点了赞。 - ehambright

1
使用cygwin bash进行切割。
  :: e.g. FILE=basename.mp4 => FILE_NO_EXT=basename
  set FILE=%1
  for /f "delims=" %%a in ('bash -c "FILE=%FILE%; echo ${FILE/.*/}" ') do set FILE_NO_EXT=%%a

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