|
wingofsea
初级用户
积分 124
发帖 34
注册 2006-5-23
状态 离线
|
『楼 主』:
[讨论]如何从用户传入的参数中去掉引号?
批处理获取到用户输入的参数,如
utility "C:\program files\utility",
如何去掉"C:\program files\utility" 的引号?
要做一些字符串拼接的操作,如
@echo off
@set arg=%1
@set file_path=%arg%\readme.txt
@for /f "usebackq delims=" %%a in (%file_path%) do set a=%%a
运行上诉代码提示:
The system cannot find the file C:\Program Files\utility"\version.txt
请问如何解决?
───────────────── 版主提示 ─────────────────
本主题讨论小结如下:
很多情况下,我们需要脱除一个字符串中可能会存在的引号,然后在加上自己的引
号使其中的特殊字符(命令连接符& 、| 、&&、||,命令行参数界定符Space 、tab 、
; 、= ,字符化转义符^ 、" ,变量化转义符% 等)字符化,失去特定的作用,而作为
普通的字符成为字符串的一个组成部分。
一、将字符串中的引号脱去的简单办法有三种,它们的功能相近,只是各自的使用
场合不同,可以处理大多数的情况。
1-1 、如果字符串存在于命令行参数%1中,可以使用%~1 脱去第一对外侧引号,如
果没有外侧引号则字符串不变;
1-2 、如果字符串存在于for 替代变量%%i 中,可以使用%%~i脱去第一对外侧引号,
如果没有外侧引号则字符串不变;
1-3 、如果字符串存在于环境变量%temp%中,可以使用%temp:"=% 脱去其中所有的
引号,如果没有引号则字符串不变;
1-4 、以上三种方案在某种程度上可以互相通用,因为它们作为变量的一种类型,
可以通过类似以下的代码或代码片断相互转移:
1-4-1、for替代变量转命令行参数: call:DeQuote %%i
1-4-2、环境变量转命令行参数:call:DeQuote %temp%
1-4-3、命令行参数转for替代变量:for %%i in (%1) do ...
1-4-4、环境变量转for替代变量:for %%i in (%temp%) do ...
1-4-5、命令行参数转环境变量:set temp=%1
1-4-6、for替代变量转环境变量:for ... set temp=%%i
二、如果字符串的引号分布情况很复杂,或者我们对被脱去引号的位置有特殊要求,
或者字符串中可能出现某些控制字符,则可以将字符串首先通过1-4 中的对应方法转存
至环境变量中,在使用以下方案或其组合进行处理:
2-1 、可以使用set var=%var:~1%脱去环境变量var 串首的第一个引号,如果串首
不存在引号则第一个字符被脱去;
2-2 、可以使用set %var:*"=% 脱去环境变量var 串首的第一个引号,如果串首不
存在引号则变量值不变;
2-3 、可以使用set var=%var:~0,-1% 脱去环境变量var 串尾的最后一个引号,如
果串尾不存在引号则最后一个被脱去;
2-4 、可以使用set "var=%var%脱去环境变量var 串尾的最后一个引号,如果串尾
不存在引号则环境变量被清空;
2-5 、可以使用set var=%var:~1,-1% 脱去环境变量var 串最外侧的一对引号,如
果串外侧不存在引号则外侧一对字符被脱去;
2-6 、可以使用%var:*"=set "var=%脱去环境变量var 串最外侧的一对引号,如果
串外侧不存在引号则出现语法错误;
2-7 、可以使用set "var=%var:"=%"脱去环境变量var 串中可能出现的所有引号,
如果串外侧不出现引号则变量值不变;与1-3 不同的是,它容许字符串的匹配引号对内
出现特殊控制字符;
───────────────── 版主提示 ─────────────────
[ Last edited by willsort on 2006-5-28 at 22:52 ]
|
|
2006-5-26 16:03 |
|
|
bagpipe
银牌会员
DOS联盟捡破烂的
积分 1144
发帖 425
注册 2005-10-20 来自 北京
状态 离线
|
『第
2 楼』:
@echo off
set arg=%1
echo %arg:"=%
set file=%arg:"=%\1.txt
echo %file%
for /f "usebackq" %%a in ("%file%") do echo %%a
其实很简单,就是没有想到罢了.............
|
|
2006-5-26 17:01 |
|
|
无奈何
荣誉版主
积分 1338
发帖 356
注册 2005-7-15
状态 离线
|
『第
3 楼』:
用 CMD 变量的扩展特性不行吗?
set arg=%~1
这样可以去掉首尾的双引号。
|
☆开始\运行 (WIN+R)☆
%ComSpec% /cset,=何奈无── 。何奈可无是原,事奈无做人奈无&for,/l,%i,in,(22,-1,0)do,@call,set/p= %,:~%i,1%<nul&ping/n 1 127.1>nul
|
|
2006-5-27 00:00 |
|
|
bagpipe
银牌会员
DOS联盟捡破烂的
积分 1144
发帖 425
注册 2005-10-20 来自 北京
状态 离线
|
『第
4 楼』:
为什么我老是找不到最佳方法呢?伤心.........受教中.............
|
|
2006-5-27 14:57 |
|
|
willsort
元老会员
Batchinger
积分 4432
发帖 1512
注册 2002-10-18
状态 离线
|
『第
5 楼』:
Re 无奈何:
实际上,这个问题还要比你我想象的要复杂一些。
首先,bagpipe兄的代码更适合脱去环境变量的引号,而兄的代码则更适合脱去命令行参数的引号,二者互有所长。
其次,无论是哪种方法,都存在无法切实约束串内特殊字符的缺点。
比如,有变量test1="C:\Program files",而如果使用兄的方法[1],则files将丢失;又比如,有变量test2="echo test>sample.txt",无论使用何种方法,都会导致程序意外产生的垃圾文件。
这我在namejm兄的主题曾略有提及,只是语焉不详,现在在这里提出,作为一个课题讨论一下,欢迎各位版主达人不吝赐教。
call:DeQuote "%test1%"
:DeQuote
set "return=%~1"
goto:eof [ Last edited by willsort on 2006-5-27 at 21:26 ]
|
※ Batchinger 致 Bat Fans:请访问 [讨论]批处理编程的异类 ,欢迎交流与共享批处理编程心得! |
|
2006-5-27 18:17 |
|
|
3742668
荣誉版主
积分 2013
发帖 718
注册 2006-2-18
状态 离线
|
『第
6 楼』:
俺也来抛个砖:
:Main
set tmpVar=%1
%tmpVar:*"=set "ret=%
goto :Eof 对于字符串内有多个引号的问题无法处理,不过可以先对字符串内除了开头和结尾的引号进行转换,完了再转换回来就行了。只是抛个砖,希望能引出willsort和无奈何两位的玉出来。。
|
|
2006-5-27 19:08 |
|
|
无奈何
荣誉版主
积分 1338
发帖 356
注册 2005-7-15
状态 离线
|
『第
7 楼』:
TO willsort
兄的这段代码调用有些问题。变量值中含有引号,并作为参数传送时,参数不要用引号扩起来。这样潜在的问题是不容易确定变量值中是否含有引号,所以我习惯的做法是用 %~n 脱去引号,然后再加上引号。
Quote: |
- @echo off
- set test1="C:\Program files"
- set test2="echo test>sample.txt"
- call :DeQuote1 %test1%
- call :DeQuote2 %test2%
- goto:eof
- :DeQuote1
- set return=%~1
- echo %return%
- goto:eof
- :DeQuote2
- set return="star %~1 end"
- echo %return%
- goto:eof
-=代码着色 BY:无奈何=- |
|
|
☆开始\运行 (WIN+R)☆
%ComSpec% /cset,=何奈无── 。何奈可无是原,事奈无做人奈无&for,/l,%i,in,(22,-1,0)do,@call,set/p= %,:~%i,1%<nul&ping/n 1 127.1>nul
|
|
2006-5-27 19:28 |
|
|
willsort
元老会员
Batchinger
积分 4432
发帖 1512
注册 2002-10-18
状态 离线
|
『第
8 楼』:
Re 无奈何:
我的意思是,当我们无法预知test1/test2的串值中是否含有引号时,就无法使用特定的方法对其中的特殊字符进行约束。比如namejm兄代码中source变量,是通过set /p获取的,我们无法确知执行代码的用户有没有使用引号,或者会不会有意无意给我们的代码制造麻烦。
也就是说,当串值(不仅仅是环境变量)含有引号时,我们(在各种命令行下)引用它就不能再使用引号,而当串值不含引号时,我们又需要使用引号进行约束,而这还没有考虑到两对或更多对引号甚至奇数个引号出现的情形。而因为我们无法预先获知串值的内容,所以需要预先检测,而目前所知的任何检测都需要引用串值。引用前需要检测,检测时必须引用,这就形成了一个佯谬。
感觉上,这个问题实际上是来源于CMD匹配引号采用就近匹配,而不是就远匹配的原则。我想知道是否存在一个比较另类的办法可以解决这个问题。
Re 3742668:
你的 %tmpVar:*"=set "ret=% 一句确实妙绝,对星号在此处的用途尚不十分清楚,不知可否解释一二?
当然它也需要预先确定串值外含有引号,否则语法错误。
Re All:
目前的测试中,set "ret=%test%会将含有后引号的串值脱去一个后引号,这是可预期的结果;而没有引号的串值将整个脱去,就在意料之外了,我本猜想它会将ret=%test%作为环境变量名的一部分,因变量匹配无效而不对%ret%做任何修改的,而结果是%ret%被清除。
|
※ Batchinger 致 Bat Fans:请访问 [讨论]批处理编程的异类 ,欢迎交流与共享批处理编程心得! |
|
2006-5-27 22:06 |
|
|
3742668
荣誉版主
积分 2013
发帖 718
注册 2006-2-18
状态 离线
|
『第
9 楼』:
Well,我就按willsort兄的要求向不大了解set命令中*号作用的朋友做个简介吧:
%PATH:str1=str2%
"str1" 可以以星号打头;在这种情况下,"str1" 会从扩展结果的开始到 str1 剩余部分第一次出现的地方,都一直保持相配。
所以,在本例中会匹配第一个引号,如果不加*号的话,那么将会匹配所有的引号,那么得到的结果将是错误的。
set var=www.cn-dos.net
echo %var:.=#% rem 输出结果应该是:www#cn-dos#net
echo %var:*.=#% rem 输出结果应该是:www#cn-dos.net
pause>nul
|
|
2006-5-27 22:51 |
|
|
无奈何
荣誉版主
积分 1338
发帖 356
注册 2005-7-15
状态 离线
|
『第
10 楼』:
Re willsort
理解兄的意思了,能够办到替换串值中的所有引号,相应的问题是在传输时必须加引号扩起来。
set test="C:\Pro&gram" files"
set "test=%test:"=%"
call :DeQuote "%test1%"
Re 3742668
兄对 * 的解释不太好理解,可以分开来表述。
1、%PATH:str1=str2%
2、%PATH:*str1=str2%
其中 1 替换 PATH 中所有 str1 为 str2 ;
2 替换 PATH 中开始到 str1 部分为 str2 。
再者 echo %var:*.=#% 输出结果应该是:#cn-dos.net
|
☆开始\运行 (WIN+R)☆
%ComSpec% /cset,=何奈无── 。何奈可无是原,事奈无做人奈无&for,/l,%i,in,(22,-1,0)do,@call,set/p= %,:~%i,1%<nul&ping/n 1 127.1>nul
|
|
2006-5-27 23:21 |
|
|
willsort
元老会员
Batchinger
积分 4432
发帖 1512
注册 2002-10-18
状态 离线
|
『第
11 楼』:
Re 3742668:
受教了!也已从set /?中找到了相关信息,看来自己还需要复习数遍命令行帮助文档了。
也就是说星号在此的作用,仍然与文件名中的通配作用相似,它可以通配0到多个任意字符。只是类似的单字符通配符?尚不被支持,而且星号的位置只限于串首,不能在串中或串后出现。
|
※ Batchinger 致 Bat Fans:请访问 [讨论]批处理编程的异类 ,欢迎交流与共享批处理编程心得! |
|
2006-5-27 23:33 |
|
|
3742668
荣誉版主
积分 2013
发帖 718
注册 2006-2-18
状态 离线
|
『第
12 楼』:
嗯,谢谢无奈何指出毛病。关于*的解释嘛,不能怪我,要怪microsoft的 帮助与支持 写得不太好理解。心浮气躁,离大成始终差那么一步,呵呵。
|
|
2006-5-27 23:37 |
|
|
Climbing
铂金会员
网络独行侠
积分 6962
发帖 2753
注册 2003-4-16 来自 河北保定
状态 离线
|
『第
13 楼』:
TMD,微软的命令说明简直就象绕口令(估计他们自己也没有搞明白到底该如何说),还是3742668兄的例子来得简明易懂一些。说白了,str1前加*号,那么就会只替换环境变量中第一个出现的str1,其它的就不替换了,是这意思吧?
|
偶只喜欢回答那些标题和描述都很清晰的帖子!
如想解决问题,请认真学习“这个帖子”和“这个帖子”并努力遵守,如果可能,请告诉更多的人!
|
|
2006-5-27 23:42 |
|
|
willsort
元老会员
Batchinger
积分 4432
发帖 1512
注册 2002-10-18
状态 离线
|
『第
14 楼』:
Re Ups:
有意思的一个发现,由于密集回复导致从10楼到13楼都变成了隔层回复,不知是由于论坛同步延迟的原因,还是用户刷新延迟的问题。
另外,还不是很明白无奈何兄set "test=%test:"=%"之后再去call :DeQuote "%test1%"的缘由。
最后,就此主题略作一个小结,请大家补正:
很多情况下,我们需要脱除一个字符串中可能会存在的引号,然后在加上自己的引号使其中的特殊字符(命令连接符&、|、&&、||,命令行参数界定符Space、tab、;、=,字符化转义符^、",变量化转义符%等)进行字符化,使其失去特定的作用,而作为普通的字符成为字符串的一个组成部分。
一、将字符串中的引号脱去的简单办法由三种,它们的功能相近,只是各自的使用场合不同,可以处理大多数的情况。
1-1、如果字符串存在于命令行参数%1中,可以使用%~1脱去第一对外侧引号,如果没有外侧引号则字符串不变;
1-2、如果字符串存在于for替代变量%%i中,可以使用%%~i脱去第一对外侧引号,如果没有外侧引号则字符串不变;
1-3、如果字符串存在于环境变量%temp%中,可以使用%temp:"=%脱去其中所有的引号,如果没有引号则字符串不变;
1-4、以上三种方案在某种程度上可以互相通用,因为它们作为变量的一种类型,可以通过类似以下的代码或代码片断相互转移:
1-4-1、for替代变量转命令行参数: call:DeQuote %%i
1-4-2、环境变量转命令行参数:call:DeQuote %temp%
1-4-3、命令行参数转for替代变量:for %%i in (%1) do ...
1-4-4、环境变量转for替代变量:for %%i in (%temp%) do ...
1-4-5、命令行参数转环境变量:set temp=%1
1-4-6、for替代变量转环境变量:for ... set temp=%%i
二、如果字符串的引号分布情况很复杂,或者我们对被脱去引号的位置有特殊要求,或者字符串中可能出现某些控制字符,则可以使用以下方案:
2-1、可以使用%test:*"=%脱去环境变量test串首的第一个引号,如果串首不存在引号则变量值不变;
2-2、可以使用set "test=%test%脱去环境变量test串尾的最后一个引号,如果串尾不存在引号则变量值被清空;
2-3、可以使用%test:*"=set "test=%脱去环境变量test串最外侧的一对引号,如果串外侧不存在引号则出现语法错误;
2-4、可以使用set "test=%test:"=%"脱去环境变量test串中可能出现的所有引号,如果串外侧不出现引号则变量值不变;与1-3不同的是,它可以容许字符串的匹配引号对内出现特殊控制字符。
[ Last edited by willsort on 2006-5-28 at 01:22 ]
|
※ Batchinger 致 Bat Fans:请访问 [讨论]批处理编程的异类 ,欢迎交流与共享批处理编程心得! |
|
2006-5-28 00:49 |
|
|
无奈何
荣誉版主
积分 1338
发帖 356
注册 2005-7-15
状态 离线
|
『第
15 楼』:
Re willsort
总结的很详细,大众的智慧是无穷的^_^。
关于 call :DeQuote "%test1%" 只是想说明当串值中含有特殊字符时,在传递和调用的过程中必须加引号以使其失去特殊性。不然会解释为多个参数或多个命令。
|
☆开始\运行 (WIN+R)☆
%ComSpec% /cset,=何奈无── 。何奈可无是原,事奈无做人奈无&for,/l,%i,in,(22,-1,0)do,@call,set/p= %,:~%i,1%<nul&ping/n 1 127.1>nul
|
|
2006-5-28 01:05 |
|