找回密码
 注册
搜索
[新手上路]批处理新手入门导读[视频教程]批处理基础视频教程[视频教程]VBS基础视频教程[批处理精品]批处理版照片整理器
[批处理精品]纯批处理备份&还原驱动[批处理精品]CMD命令50条不能说的秘密[在线下载]第三方命令行工具[在线帮助]VBScript / JScript 在线参考
查看: 20271|回复: 11

[文件操作] 可能是一个老问题,for 对带空格文件名的处理

[复制链接]
发表于 2024-6-14 11:39:56 | 显示全部楼层 |阅读模式
本帖最后由 DOSforever 于 2024-6-17 07:56 编辑

比如有若干个 *.txt 文件,其中有一个或多个带空格的文件名 filename with spaces.txt

for %f in (*.txt) do dir "%f" ,set 是通配符的时候引用 %f 必须加双引号,否则的话会提示找不到文件;
for %f in ("filename with spaces.txt") do dir %f ,set 不是通配符,只有单文件名的时候 %f 必须不加双引号,否则的话会提示找不到文件;
但如果
for %f in ("*.txt") do dir %f ,在 set 上加双引号是无效的,遇到通配符中有空格的文件名仍然会提示找不到文件;
for %f in ("filename with spaces.txt") do dir "%f" ,在 set 和 %f 上同时加双引号,遇到 set 是带空格的单一文件名是无效的,会提示找不到文件;

那么 set 中有时候是通配符,有时候是单文件名,也可能是多个通配符和单文件名在一起,比如
for %f in (*.doc "filename with space.txt" *.xls) do dir %f
那么后面的 %f 一会儿要加双引号,一会儿不加;那么有没有办法用一种统一的格式无论是通配符还是单一文件名对 %f 的引用都可以正确处理?
发表于 2024-6-14 11:53:11 | 显示全部楼层
  1. dir "%~f"
复制代码

评分

参与人数 1技术 +1 收起 理由
DOSforever + 1 有效

查看全部评分

发表于 2024-6-14 13:08:50 | 显示全部楼层
回复 2# 77七


我喜欢使用 for /f 把杂七杂八的交给 dir 去处理,爱咋滴咋滴,反正我 for /f 格式固定
  1. @echo off
  2. for /f "delims=" %%i in ('dir /b /a-d *.doc "filename with space.txt" *.xls') do (
  3.     echo %%i
  4. )
  5. pause
复制代码
发表于 2024-6-14 13:15:30 | 显示全部楼层
本帖最后由 aloha20200628 于 2024-6-14 13:26 编辑

回复 1# DOSforever

一。用法逻辑的说明
   for %f in ("a * c.txt" "*&*.bat") do ...
   for /f "delims=" %f in (' dir /b "a * c.txt" "*&*.bat" ') do ...
以上两式等效,故择其一即可,不必在 set 中和 do ... 中复用同类功能
二。建议用双引号包裹每个文件名表达项
   for %f in ("a * c.txt" "*&*.bat") do echo,%f
   for %f in ("a * c.txt" "*&*.bat") do echo,%~f
以上两式的echo输出结果等效(即 %f 与 %~f 相同);关键是set中的每个文件名表达项,采用双引号包裹是为防止内含的空格或特殊字符如&被转义
发表于 2024-6-14 14:39:46 | 显示全部楼层
回复 3# Batcher


   感谢站长分享!其实有时候揣摩楼主的意思挺难的,只要语法没错,我就当举了个例子,不去考虑是否符合实际了,或许楼主有特殊的用途。
发表于 2024-6-14 15:18:54 | 显示全部楼层
本帖最后由 77七 于 2024-6-14 15:21 编辑
  1. for %%a in () do
复制代码
这种句式,我理解有两种用法,

如果 ()内的字符串含有通配符 *? ,则会匹配文件,这时候返回的结果不带引号。

如果 () 内不含通配符,就当作普通字符串处理,和目录下有无该文件没有关系。只不过如果字符串有特殊符号(包括这种句式的分隔符 空格、等号、分号、逗号、制表符,及批处理语法中其它特殊符号,比如& | ^ < >),需要用引号括起来,这时候返回的结果是带引号的。如果没有特殊符号,则加引号返回引号,不加则不返回引号。

如果 () 内既有 *.txt 又有  "1空格2.doc" ,返回的结果依照上述规则分别返回。

另外dir 的问题,大概是4种情况 dir ""1.txt"" 、dir ""1 2.txt"" 、dir 1 2.txt 、dir 12.txt
其中第一、二种 情况,大概和buyiyang大佬讲到的另一帖情况相似(http://www.bathome.net/redirect.php?goto=findpost&;ptid=68005&pid=281417),当 字符串没有空格时,多加一对引号没有影响,否则不行。
第三、四种情况,不必说了。
 楼主| 发表于 2024-6-15 08:06:16 | 显示全部楼层
77七 发表于 2024-6-14 11:53

        试下来还是你这方法有效。要在 set 单文件名和 do 后面的 %f 两者都加上双引号,但要使用 %~f 这样的语法。也就是要用
for %f in (*.doc "filename with spaces.txt" *.xls) do dir/b "%~f" 这样的格式,
这样无论 set 中是通配符还是用双引号包裹起来的单一文件名都可以正确处理。

其他两位给出的方式不行,看上去是对的,但实际不行,因为用 echo 做测试有一定的局限性,echo 只能让你看看变量所获取的 token 是否是所期望的那样,但对这个 token 能否正确操作是另外一回事,因为我的操作是针对具体的文件,并不是无“实体”的字符串,所以光获取正确的 token 字符串还不行,还要看命令能否“正确”理解这个字符串,所以有一定要用 dir , ren , copy 等实际对文件操作的命令去验证。
 楼主| 发表于 2024-6-15 08:44:00 | 显示全部楼层
本来对这个 %~f 语法还没注意,刚看到此说明的时候不知道是干什么的,现在想起来当年开发者专门设置了这样一个语法是不是就是为了解决 set 中有双引号引起的混乱问题?
发表于 2024-6-16 18:40:43 | 显示全部楼层
回复 4# aloha20200628

这两运行大量文件时有区别吧?第一个内存占用会越来越多,第二个就没这问题。
发表于 2024-6-16 19:31:01 | 显示全部楼层
回复 9# Ru_Evan

用实测数据可验证采用 dir /b/s/a-d, for /r %%F in (*) 和 for /f "delims=" %%F in ('dir /b/s/a-d') 这三者获取文件列表的效能区别:
其一,搜索约有3万个文件的目录树并生成其全部文件列表的用时比较
        0.42s》dir /b/s/a-d>files.lst
        1.16s》(for /r %%F in (*) do echo,%%F)>files.lst
        22.6s》(for /f "delims=" %%F in ('dir /b/s/a-d') do echo,%%F)>files.lst
其二,for %%F in (*) 不能匹配隐藏文件,匹配表达式不能包含路径
当匹配文件数过千时,速度差别会愈趋明显,过万了就应采用第一方法,即使会产生临时文件也是值得的...
发表于 2024-6-16 23:15:27 | 显示全部楼层
本帖最后由 newswan 于 2024-6-16 23:20 编辑

回复 10# aloha20200628

测试 powershell 呢

  1. $f = Get-ChildItem -Path "D:\share" -Recurse
  2. $f.FullName | Out-File -FilePath  "a.txt" -Encoding 'utf8'
复制代码
发表于 2024-6-17 11:41:13 | 显示全部楼层
本帖最后由 aloha20200628 于 2024-6-17 11:42 编辑


在10楼原测试方案中加入powershell两个测试方法(均在cmd命令行运行多次后取稳定且最少用时结果),更新实测对比结果如下:
        搜索约有3万个文件的目录树并生成其全部文件列表的用时比较
        0.42s(1.0单位时)》dir /b/s/a-d>files.lst
        1.16s(2.8单位时)》(for /r %%F in (*) do echo,%%F)>files.lst
        19.1s(45.5单位时)》(for /f "delims=" %%F in ('dir /b/s/a-d') do echo,%%F)>files.lst
        2.03s(4.8单位时)》powershell "$s=(dir -r).fullname;sc files.lst $s"
        2.64s(6.3单位时)》powershell "(dir -r).fullname|sc files.lst"
您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|手机版|小黑屋|批处理之家 ( 渝ICP备10000708号 )

GMT+8, 2026-3-18 01:42 , Processed in 0.021069 second(s), 8 queries , File On.

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表