中国DOS联盟论坛

中国DOS联盟

-- 联合DOS 推动DOS 发展DOS --

联盟域名:www.cn-dos.net  论坛域名:www.cn-dos.net/forum
DOS,代表着自由开放与发展,我们努力起来,学习FreeDOS和Linux的自由开放与GNU精神,共同创造和发展美好的自由与GNU GPL世界吧!

游客:  注册 | 登录 | 命令行 | 会员 | 搜索 | 上传 | 帮助 »
中国DOS联盟论坛 » DOS批处理 & 脚本技术(批处理室) » [讨论]如何从用户传入的参数中去掉引号?
« [1] [2] »
作者:
标题: [讨论]如何从用户传入的参数中去掉引号? 取消高亮 | 上一主题 | 下一主题
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
查看资料  发送邮件  发短消息 网志  OICQ (105400208)  编辑帖子  回复  引用回复
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:

  1. @echo off
  2. set test1="C:\Program files"
  3. set test2="echo test>sample.txt"
  4. call :DeQuote1 %test1%
  5. call :DeQuote2 %test2%
  6. goto:eof

  7. :DeQuote1
  8. set return=%~1
  9. echo %return%
  10. goto:eof

  11. :DeQuote2
  12. set return="star %~1 end"
  13. echo %return%
  14. 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
查看资料  发送邮件  发短消息 网志  OICQ (105400208)  编辑帖子  回复  引用回复
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
查看资料  发送邮件  发短消息 网志  OICQ (105400208)  编辑帖子  回复  引用回复
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
查看资料  发送邮件  访问主页  发短消息 网志  OICQ (653668)  编辑帖子  回复  引用回复
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
查看资料  发送邮件  发短消息 网志  OICQ (105400208)  编辑帖子  回复  引用回复
« [1] [2] »
请注意:您目前尚未注册或登录,请您注册登录以使用论坛的各项功能,例如发表和回复帖子等。


可打印版本 | 推荐给朋友 | 订阅主题 | 收藏主题



论坛跳转: