标题: [未彻底解决]多个文件拖到cmd窗口后,如何获取每一文件的完整路径 [打印本页]
作者: namejm 时间: 2010-4-5 23:44 标题: [未彻底解决]多个文件拖到cmd窗口后,如何获取每一文件的完整路径
cmd窗口有一个特点:支持把文件拖曳到cmd窗口中来处理。
编个十分简单的脚本来演示一下:复制代码
一般的情形是这样的:
1、当文件的完整路径中带有空格的时候,cmd窗口将自动为文件的完整路径首尾添加一对引号。例如,把 d:\abc xyz 文件夹下的 test.txt 文件拖曳到以上代码所在的脚本文件上之后,将在屏幕上显示: "d:\abc xyz\test.txt"
2、当文件的完整路径中没有空格的时候,cmd窗口将不会为文件的完整路径添加引号对。例如:把 d:\abcxyz 文件夹下的 test.txt 文件拖曳到以上代码所在的脚本文件上之后,将在屏幕上显示: d:\abcxyz\test.txt。请注意,这个时候,文件路径里没有引号对。
当然,这只是一般情形。还有一种特殊情形:当文件的完整路径中有&但是不带空格的时候,以上代码将捕获不到正确的路径。比如:把 d:\abcxyz 文件夹下的 test1&test2.txt 文件拖曳到以上代码所在的脚本文件上之后,屏幕上显示的不是 d:\abcxyz\test1&test2.txt,而是显示: d:\abcxyz\test1,也就是说,&后的字符串直接被丢弃掉了。这可能是cmd窗口在捕获or传递参数时的一个bug。
假设 d:\test 目录下有如下文件,现在把它们同时拖曳到脚本文件上来执行,需要获得每一个文件的完整路径,请问如何编写代码?- abc.txt
- abc xyz.txt
- abc^xyz.txt
- abc&xyz.txt
- abc & xyz.txt
- (abc)(xyz).txt
- (abc) (xyz).txt
- (abc)&(xyz).txt
- (abc) & (xyz).txt
- abc;xyz.txt
- abc,xyz.txt
- abc=xyz.txt
复制代码
想到这个问题,是源于这个帖子的讨论: 如何用批处理批量移动文件或文件夹?(http://bbs.bathome.net/thread-7504-1-1.html)
提示:一般情况下,可以用如下代码显示多个文件的完整路径:复制代码
=====================================================
qzwqzw 在7楼给出了解释:
用批处理的办法基本无解
这个问题源于Explorer的拖放扩展程序shell32.dll
注册表路径位于HKEY_CLASSES_ROOT\CLSID\{86C86720-42A0-1069-A2E8-08002B30309D}
因为它没有将“&"视为转义符号
所以不会用引号对将其扩起取消转义
所以对于这个问题无非以下几个方案:
1、修改拖放扩展程序shell32.dll,让它可以处理"&"的情况;
2、新建拖放扩展程序,专门处理cmd之类程序的路径过滤;
3、在处理前告知用户使用"&"的情况可能出错,交由用户处理发生的异常;
既然这样,那么,用批处理来做的话,只好不去兼容带&但不同时带空格的完整路径这一情况了(路径中带有^符号也不行,头疼ing)。演示代码如下:- @echo off
- set str=%*
- set "str=%str:"=%"
- set "str= %str%"
- call set "str=%%str: %~d1=" "%~d1%%"
- for %%i in ("%str%") do echo %%i
- pause
复制代码
作者: solitude 时间: 2010-4-5 23:52
是%1么?
我记得好像是%0
作者: lxzzr 时间: 2010-4-6 00:47
能提取这样的:abc & xyz.txt,却不能提取abc&xyz.txt,郁闷....
题是好题....
作者: mm546863903 时间: 2010-4-6 08:14
额,有点难度啊,思考中。。。
作者: GNU 时间: 2010-4-6 09:29 标题: 回复 2楼 的帖子
相当明显,你记错了。
作者: caruko 时间: 2010-4-6 09:50
既然是拖到窗口...那么就是系统自动完成的...
要在这个阶段用BAT脚本插手是没办法的..
只能在接受到1%以后,再做路径判断..有问题自动补偿完整
作者: qzwqzw 时间: 2010-4-6 11:41
用批处理的办法基本无解
这个问题源于Explorer的拖放扩展程序shell32.dll
注册表路径位于HKEY_CLASSES_ROOT\CLSID\{86C86720-42A0-1069-A2E8-08002B30309D}
因为它没有将“&"视为转义符号
所以不会用引号对将其扩起取消转义
所以对于这个问题无非以下几个方案:
1、修改拖放扩展程序shell32.dll,让它可以处理"&"的情况;
2、新建拖放扩展程序,专门处理cmd之类程序的路径过滤;
3、在处理前告知用户使用"&"的情况可能出错,交由用户处理发生的异常;
作者: netbenton 时间: 2010-4-6 18:56 标题: ¥¥¥重大发现¥¥¥!!!!!!
不带空格的目录中含有&号时,&会把后面字符串的作为一个新的项目去执行!
前面没了%0,只是字符串单独作为一个新命令行的在裸奔!!!
如下面的目录:
“新建文件夹¬epad¬epad¬epad”
当拖曳到一楼的示范批处理,在按了任意键之后,会连续打开3次记事本!!!!
神吧!!!目录也可以作为命令去运行程序了
作者: yangfengoo 时间: 2010-4-6 21:59 标题: 回复 8楼 的帖子
作用实在有限,恶作剧或者掩饰命令还可以
作者: zqz0012005 时间: 2010-4-9 21:09
应该算是大家都知道的老经验了吧,对于%x参数引用较保险的做法是"%~x"
怎么又重新讨论了呢?
作者: netbenton 时间: 2010-4-9 22:02
不是那个意思了,其实这个问题是不可能解决的,因为有&在路径中后,系统把成多个任务去看了,
像这个:
“...\新建文件夹¬epad¬epad¬epad”
把它拖到:abc.bat后
其实在cmd窗口执行了四次任务了:
1, abc.bat ...\新建文件夹
2, notepad
3, notepad
4, notepad
如此一来,又怎么可能让abc.bat得到完整的路径参数呢?系统根本就没有打算给它。
作者: 523066680 时间: 2010-4-9 22:26
- @echo off
- :a
- if not "%~1"=="" (echo "%~1" &shift /1 &goto :a)
- pause
复制代码
没看出来……
啊我现在才知道可以多个文件同时拖放并获取各个文件名,OUT了……
!!!!
-O_o - 楼上本顿的技术飚到30了呵
_[ ]__
[ 本帖最后由 523066680 于 2010-4-9 22:38 编辑 ]
作者: Spring 时间: 2010-4-9 23:46
原帖由 zqz0012005 于 2010-4-9 21:09 发表
应该算是大家都知道的老经验了吧,对于%x参数引用较保险的做法是"%~x"
怎么又重新讨论了呢?
在 D 盘根目录新建一个文本文档,命名为 "R&B.txt" ,也就是创建一个文本文档 “D:\R&B.txt” ,
现在讨论的问题是把它拖到一个内容为
@echo off
echo %*
pause
的批处理文件上,怎样能使批处理能显示 D:\R&B.txt
作者: todayambition 时间: 2010-4-10 10:33
@echo off
echo %*
pause
中用%*接收全部参数都没有得到abc&xyz.txt,应该是不行的
不过,把要此批处理显示路径的所有文件放到一个文件夹(如:d:\temp\)下,再dir d:\temp\*.txt /b
就得到了所要的路径
作者: x9tiancmd 时间: 2010-4-10 23:10
发觉大家,都有点太为难 set/p 命令了
哈哈, 不过 也只有这样才能长知识长见识○( ̄﹏ ̄)○
作者: namejm 时间: 2010-4-10 23:27
原帖由 todayambition 于 2010-4-10 10:33 发表
@echo off
echo %*
pause
中用%*接收全部参数都没有得到abc&xyz.txt,应该是不行的
不过,把要此批处理显示路径的所有文件放到一个文件夹(如:d:\temp\)下,再dir d:\temp\*.txt /b
就得到了所要的路径
把多个文件拖曳到cmd窗口来处理,其实是添加了人机互动的环节,能带来更大的灵活性,这是用 dir 命令所无法企及的。
作者: todayambition 时间: 2010-4-11 11:59 标题: 回复 16楼 的帖子
呵呵 namejm说的没错,而且我发现c语言也有这功能,有意思。
我的原意是将多个文件放入一个文件夹,然后将文件夹拖到cmd窗口,然后用dir %1得到所要的文件路径,避免了显示如abc&xyz.txt这样名字的文件的路径时出错
作者: GNU 时间: 2010-4-11 12:18
我始终认为,批处理就应该是一次双击全部搞定,拖放=蛋疼。
作者: cjiabing 时间: 2010-8-20 22:05
经过一个下午的努力,终于有了结果,效率不是很高,但还是基本能够实现目标。第一次来挑战区,请多多指教。- echo.>abc.txt
- echo.>"abc xyz.txt"
- echo.>"abc^xyz.txt"
- echo.>"abc&xyz.txt"
- echo.>"abc & xyz.txt"
- echo.>"(abc)(xyz).txt"
- echo.>"(abc) (xyz).txt"
- echo.>"(abc)&(xyz).txt"
- echo.>"(abc) & (xyz).txt"
- echo.>"abc;xyz.txt"
- echo.>"abc,xyz.txt"
- echo.>"abc=xyz.txt"
复制代码
可以同时拖拉多个文件到批处理中,最后获取这几个文件的完全合格文件名。
文件名含有空格的也可以实现。
但文件名中含有(.)与(&)的,后缀名非三位(如.db、html)的无法读取——需要重新设置。
不处理文件夹。
已经支持的后缀名有:txt;doc;exe;rar;mp3;jpg;wma;bat,其它格式需补充。
可能与 “echo %*”有关,重定向时自动放到“%USERPROFILE% ”中去了,只好用 “>>%~dp0”。
由于用了两对重复的FOR,特别是设置“hzm”的FOR,导致速度下降。
应该也支持从单个文本内容中提取路径名。方法是将“~dp0_2tyxs.txt”改为该文本名称。
其它方面有待完善。
- @echo off&setlocal enabledelayedexpansion
- echo %*>>"%~dp0_test.txt"
- echo.>"%~dp0_test2.txt"
- echo.>"%~dp0_results.txt"
- for /f "usebackq tokens=*" %%i in ("%~dp0_test.txt") do (
- set var=%%i
- for /l %%a in (0,1,1000) do (
- set /a ddl=%%a-1
- set str2=!var:~%%a,2!
- if "!str2!"==":\" call echo %%var:~!ddl!,1%%!var:~%%a,1000!>>"%~dp0_test1.txt"
- )
- )
- for %%l in (txt;doc;exe;rar;mp3;jpg;wma;bat;htm;pdf;ppt) do (
- set hzm=%%l
- for /f "usebackq tokens=*" %%i in ("%~dp0_test1.txt") do (
- set var=%%i
- for /l %%a in (0,1,1000) do (
- set /a ddf=%%a+4
- set str=!var:~%%a,4!
- if "!str!"==".!hzm!" echo !var:~0,%%a!.!hzm!>>"%~dp0_test2.txt"
- )
- )
- for /f "usebackq tokens=1,2,3,4 delims=." %%a in ("%~dp0_test2.txt") do (
- set vara=%%a
- set varb=%%b
- if /i "!varb:~0,3!"=="!hzm!" echo !vara!.!varb:~0,3!>>"%~dp0_test3.txt"
- )
- )
- for /f "usebackq delims=" %%a in (`sort "%~dp0_test3.txt"`) do (
- if not %%a equ !b! echo %%a>>"%~dp0_results.txt"
- set b=%%a)
- del "%~dp0_test.txt"
- del "%~dp0_test1.txt"
- del "%~dp0_test3.txt"
- del "%~dp0_test2.txt"
- start "" "%~dp0_results.txt"
- EXIT
复制代码
[ 本帖最后由 cjiabing 于 2010-8-21 10:42 编辑 ]
作者: cjiabing 时间: 2010-10-9 21:04
晕掉,以前长篇大论都没达到效果,以下几个字就解决了!~
因为用的是FOR,不支持那些变态文件,但基本上能满足一般使用了,比如拖入MP3播放。
- @echo off
- for /f "tokens=*" %%a in ("%*") do (
- for %%i in (%%a) do if exist %%i echo %%i
- )
- pause
复制代码
作者: CrLf 时间: 2011-2-6 23:56
楼上这么麻烦干嘛?一句话的事:
for %%a in (%*) do echo %%~fa
这样说来,难道以后拖放只能用set /p了吗?
set /p n=&&for /f %%a in ("%n:"=%") do echo %%~fa
作者: yhcbird 时间: 2011-2-10 17:28
原帖由 GNU 于 2010-4-11 12:18 发表
我始终认为,批处理就应该是一次双击全部搞定,拖放=蛋疼。
是啊,太蛋疼了,批处理如果要进行要拖放失去了批处理的快捷高效。。。。一点意思都没有。。。
作者: slore 时间: 2011-3-25 17:32
用批处理的办法基本无解
这个问题源于Explorer的拖放扩展程序shell32.dll
注册表路径位于HKEY_CLASSES_ROOT\CLSID\{86C86720-42A0-1069-A2E8-08002B30309D}
因为它没有将“&"视为转义符号
所以不会用引号对将其 ...
qzwqzw 发表于 2010-4-6 11:41
说下,和shell32.dll没关系,明显是cmd的事情。。。
作者: qzwqzw 时间: 2011-4-29 16:26
本帖最后由 qzwqzw 于 2011-4-29 16:30 编辑
说下,和shell32.dll没关系,明显是cmd的事情。。。
slore 发表于 2011-3-25 17:32
呵呵
这可真是公说公有理婆说婆有理了
cmd怪shell32不把&用引号包裹住再交过来
shell32怪cmd自己不把赤裸的&管教好
一嘴烂账没法说清
不过又回头多想了一下
这个问题仍有探索的余地
余地就在%cmdcmdline%
那里包裹了更多的信息
想办法处理了一下
因为以前很少关注转义字符的处理
费了许多功夫才大致完成
最终的结果是给定的12个特殊文件处理了11个
唯一剩下的一个(abc)&(xyz).cmd
没什么好办法
因为它直接导致批处理无法启动- :: 测试多个怪僻文件名直接拖拽到批处理文件上,批处理是否正确处理这些文件名
- @echo off
- rem pause
- if not [%1]==[] goto :start
- echo 正在生成测试文件
- echo.>abc.cmd
- echo.>"abc xyz.cmd"
- echo.>"abc^xyz.cmd"
- echo.>"abc&xyz.cmd"
- echo.>"abc & xyz.cmd"
- echo.>"(abc)(xyz).cmd"
- echo.>"(abc) (xyz).cmd"
- rem echo.>"(abc)&(xyz).cmd"
- echo.>"(abc) & (xyz).cmd"
- echo.>"abc;xyz.cmd"
- echo.>"abc,xyz.cmd"
- echo.>"abc=xyz.cmd"
- echo @echo 溢出漏洞存在!^&pause>xyz.cmd
- echo 测试文件生成.
- goto :eof
-
- :start
- echo starting...
- set _line="%cmdcmdline:"="%"
- set _line=%_line:^=^%
- set _line=%_line:&=&%
- set _line=%_line:(=(%
- set _line=%_line:)=)%
- set _line=%_line:,=,%
- set _line=%_line:;=;%
- set _line=%_line: =□%
- rem set _line
- rem pause
- setlocal EnableDelayedExpansion
- for %%f in (%_line:~1,-1%) do set _line2=!_line2!=%%f
- endlocal & set _line=%_line2:□= %
- set _line=%_line:"="%
- set _line=%_line:~9,-1%
- rem set _line
- rem pause
- setlocal EnableDelayedExpansion
- for %%f in (%_line%) do (
- set _file="%%~f"
- set _file=!_file:^=^^!
- set _file=!_file:&=^&!
- set _file=!_file:(=^(!
- set _file=!_file:)=^)!
- set _file=!_file:,=,!
- set _file=!_file:;=;!
- set _file=!_file:===!
- if exist !_file! (echo ---!_file!---) else (echo ___"%%~f"____)
- )
- endlocal
- echo 结束
- pause
复制代码
另外
转义字符的处理过程中
又遇到了等号的替换问题
顺便提供了一种新思路- @echo off & setlocal EnableDelayedExpansion
- set _exp=var=value
- set _exp
- set _exp=%_exp:===%
- set _exp
- echo 全角等号可以直接替换
- pause
- set _exp=var=value
- set _exp
- for %%f in ("=") do (
- call set _exp=!_exp:%%~f=-!
- )
- set _exp
- echo 半角等号不能直接替换
- pause
- set _exp=var=value
- set _exp
- set _exp=%_exp: =□%
- set _exp=%_exp:;=;%
- for %%e in (%_exp%) do set _exp2=!_exp2!=%%e
- set _exp=%_exp2:□= %
- set _exp=%_exp:;=;%
- set _exp=%_exp:~1%
- set _exp
- echo 转折的办法:把非等号的for分隔符替换掉,再用for遍历被等号分隔的所有串,并且用等号的替换字符连接这些串,最后将其它分隔符恢复,不支持处理连续的等号
- pause
复制代码
作者: zqz0012005 时间: 2011-4-29 19:39
qzw居然把我那个例子拿出来了,这应该是cmd.exe自身的BUG,解析命令行有缺陷。应该无解,除非让微软打补丁。
替换等号那个,无法兼容特殊字符。对特殊字符的处理存在不足是cmd.exe的根本缺陷。只有研究它的源码才知道问题在何处。
PS:最近工作中经常涉及对字符串的解析与处理,发现不少问题,比如内存泄露、踩内存、逻辑问题之类的,这玩意的确很让人头疼。
作者: qzwqzw 时间: 2011-4-30 19:51
qzw居然把我那个例子拿出来了
zqz0012005 发表于 2011-4-29 19:39
恕我无知
竟然不知道那段文字引用了你哪个例子
关于等号替换
我认为稳妥的办法还是逐个字符检测
特殊字符可以另行处理- @echo off
- set _exp=if "%%a%%"=="%%b%%" echo 2^^3=8^>out.txt
- set _exp
- set "_exp=%_exp:"="%"
- :loop
- if "%_exp:~0,1%"=="=" (
- set "_exp2=%_exp2%="
- ) else (
- set "_exp2=%_exp2%%_exp:~0,1%"
- )
- set "_exp=%_exp:~1%"
- if not "%_exp%"=="" goto :loop
- set "_exp=%_exp2:"="%"
- set _exp2=
- set _exp
- echo 老实的办法:逐个字符判断是否等号,是则替换,不是则直接连接
- pause
复制代码
作者: zqz0012005 时间: 2011-5-5 23:40
原来兄不在论坛管理群,倒忘了以前在群里是哪几个人讨论过此问题。
当时我用的例子和你这个类似(另外还用了VBS监控进程创建来观察%cmdcmdline%),真是英雄所见略同。
作者: techon 时间: 2011-5-9 22:40
本帖最后由 techon 于 2011-5-10 01:45 编辑
原来是这样的。。。只要路径或文件名中有空格 就会加上引号从而处理任何文件名,
路径和文件名都没有空格,但是有特殊符号时 如 & ^ % 等 则会出现错误。。。
怪不得我在桌面上找了一堆文件都没问题呢
作者: powerbat 时间: 2011-5-9 23:32
为什么不试试这个:
(abc)&(xyz).txt
作者: techon 时间: 2011-5-10 00:17
本帖最后由 techon 于 2011-5-10 01:51 编辑
这个cmd shell 不给力 改天试试 PowerShell
作者: techon 时间: 2011-5-10 00:53
本帖最后由 techon 于 2011-5-10 02:16 编辑
没什么好办法了?。。。
作者: cjiabing 时间: 2011-6-3 13:24
本帖最后由 cjiabing 于 2011-6-3 13:27 编辑
21# zm900612
忘记怎么说了,从实践总结出来的!~
或许,外面的FOR真的多余了,有空研究清楚了再说说道理!~
作者: cjiabing 时间: 2012-2-23 00:32
本帖最后由 cjiabing 于 2012-2-23 00:35 编辑
我弱弱地问,以下代码满足了楼主的要求没有?
首先,用dir来获得文件的路径(我经常用if 、dir、%fa来干这种事),有点罗嗦,对文件夹无效,可惜无法用if exist。
第二、既然%*能保存所有参数,那么把这些含有特殊符号的参数全部输入到dir,而dir是不会对文件进行操作的,所以它也可以保存内容。
第三、for虽然也是逐行逐个处理,遇到特殊符号会发生错误。但对于集合内的命令执行结果它们却视而不见,你可以先ipconfig再for,而不必考虑它输出来的是什么。- @echo off
- ::显示所有拖入文件的路径,完美支持楼主提供的含有特殊符号的文件名。唯一不足的是不支持文件夹,文件夹需要另外想办法。
- echo 以下是文件:
- dir /b %*
- pause
-
- ::计算拖入文件的个数,用来验证。
- dir /b %*|findstr /n /i .*
- pause
-
- @echo off&setlocal enabledelayedexpansion
- ::决定还是用FOR来验证,避免无法继续下一步操作。
- set num=0
- for /f "tokens=*" %%a in ('dir /b %*') do set /a num+=1&echo;!num!:%%a
- pause
复制代码
作者: 幼稚园 时间: 2012-8-10 08:36
本帖最后由 幼稚园 于 2012-8-10 09:34 编辑
果然好难啊!
29楼的(abc)&(xyz).txt.txt拖到批处理上,在传递参数时就发生错误了!
潜水学习......
作者: qwe274208829 时间: 2012-8-15 21:56
顶下
作者: flaven 时间: 2013-7-4 13:00
回复 33# cjiabing
建了个文件,名为 4~@%#$!^&=().jpg,拖进去不行。。。
作者: cjiabing 时间: 2013-7-5 21:55
回复 36# flaven
奇怪,我放在桌面上可以执行,放到驱动盘下就出错了!~
可能路径名含有空格的时候它自动添加双引号,没有空格的时候它没有添加,所以出错了!~
原理是这样的:
1.对于“%*”直接使用 "%*" (即echo "%*")即可解决问题,但问题是这个结果中的路径都挤到了一行里面,不方面引用。
因此需要考虑第二个问题:拆分路径并去掉双引号。
2.一般情况下,利用dir命令的特点来自动拆分路径和双引号,所以使用 dir /b %* 即可。但现在看来也是存在一定限制。
3.实在不行的情况下,又得回头使用SET替换的方式,或者使用FOR替换的方式,那样会比较麻烦点。
因为文件名含有特殊符号,所以使用双引号,但为了提前单个独立的路径又需要去掉双引号,这是一个矛盾,解决了这个问题就可以解决了这个难题。
作者: flaven 时间: 2013-7-7 15:03
回复 37# cjiabing
上周我遇到类似问题,搞了一星期试了各种方法搞不定
后来换了vbs来处理,处理完再把结果作为参数传递给bat启动,搞定
作者: wskwfkbdn 时间: 2016-1-28 13:11
bat默认把运行参数使用空格符进行分割,即使能够把&进行转义处理,但包含空格的完整路径,将得不到完整的路径。唯一办法:%*接收所有参数,对参数进行文本处理。
作者: wskwfkbdn 时间: 2016-1-29 14:42
此题有解 纯P实现,以%*接收所有参数,然后使用for命令分割处理。
作者: CommandBatCmd 时间: 2017-2-1 22:37
多数时间是从技巧上寻找突破口,但只要把批处理的
预处理、变量扩展(%time%等)、延迟变量扩展(!time!等)、特殊字符(路径文件名与批处理共享的 ! % & ( ) , ; = ^ 等)
这四个核心概念放到一起,来分析楼主抛出的难题,感觉修改标题为【已解决】的可能性很小!
欢迎光临 批处理之家 (http://www.bathome.net/) |
Powered by Discuz! 7.2 |