Board logo

标题: [系统相关] [讨论]分离%path%路径的一段批处理 [打印本页]

作者: namejm    时间: 2009-5-18 22:12     标题: [讨论]分离%path%路径的一段批处理

  曾经在CN-DOS上看到ansipeter同志(曾用马甲:9527、bigpipe)发表的一段代码,可以很方便地分离出%path%中的每一条路径,揣摩良久,不得其解,发布在此,望各位能详加探讨其中奥妙:
  1. for %a in ("%path:;=" "%") do @echo %~a
复制代码
  原帖出处:http://www.cn-dos.net/forum/viewthread.php?tid=38347
作者: netbenton    时间: 2009-5-18 22:21

若path=c:\dos;c:\windows;c:\tools
echo %path:;=" "%
结果为:c:\dos" "c:\windows" "c:\tools

echo "%path:;=" "%"
结果为:"c:\dos" "c:\windows" "c:\tools"

原来是这么回事!后面的%~a再把双引号丢掉。
作者: namejm    时间: 2009-5-18 22:33

  哈哈,真是一语点醒梦中人,竟然是用引号对来分隔字符串,而不再采用常见的空格做分隔符——为了兼容路径中可能出现的空格,只能舍弃空格做分隔符。
作者: Batcher    时间: 2009-5-18 22:33

原帖14楼有讲解,跟2楼差不多。
作者: tireless    时间: 2009-5-18 22:38

直接 for %a in (%path%) do echo %a 可以分出来。括号里面的分隔符可以是 ; , =
作者: namejm    时间: 2009-5-18 22:39

  惭愧,没仔细看那个帖子的所有讨论,错过了领会其中奥妙的大好时机。
作者: namejm    时间: 2009-5-18 22:41

原帖由 tireless 于 2009-5-18 22:38 发表
直接 for %a in (%path%) do echo %a 可以分出来。括号里面的分隔符可以是 ; , =

  碰上带空格的路径就会出错,还是顶楼的代码比较保险——当然,顶楼的代码也不能兼容带&的路径,不过,在实际使用中,是可以通过一些技巧避免掉的。

—————————————————————————————————————————————————————————
  红色部分是错误的结论,实际上,顶楼的代码可以兼容带&的路径,请看以下楼层中batcher的演示。
作者: Batcher    时间: 2009-5-18 22:41     标题: 回复 5楼 的帖子

3楼已经提到空格问题了
作者: Batcher    时间: 2009-5-18 22:48     标题: 回复 7楼 的帖子

C:\Test>test.bat
C:\BatHome\Batcher&namejm
C:\BatHome\Batcher namejm

C:\Test>type test.bat
@echo off
set "mypath=C:\BatHome\Batcher&namejm;C:\BatHome\Batcher namejm"
for %%a in ("%mypath:;=" "%") do (
  echo %%~a
)

作者: netbenton    时间: 2009-5-18 22:49

开启变量延迟后,用!号代替%号,就可以解决多个特殊符号问题了
作者: namejm    时间: 2009-5-18 22:59

  开启了变量延迟后再用!来代替%,往往会造成原有的!丢失,请看这篇文章:最大限度原样输出含特殊符号的指定行内容:http://bbs.bathome.net/viewthread.php?tid=4580
作者: netbenton    时间: 2009-5-18 23:07

可以在for内把变量延迟关掉就不会丢了
  1. @echo off&setlocal enabledelayedexpansion
  2. for %%a in ("!path:;=" "!") do (
  3.     if "!#@#!" equ "" endlocal
  4.     echo %%~a
  5. )
复制代码

[ 本帖最后由 netbenton 于 2009-5-18 23:08 编辑 ]
作者: namejm    时间: 2009-5-18 23:17

  netbenton兄12楼的代码测试过了吗?我实地测试了一下,修改之前的代码,执行结果显示的是"echo 处于关闭状态"的报错信息。

  另外,在for内,启用了变量延迟后,可以在合适的位置用endlocal来中止,就可以避免!被抛弃的问题,但是,这个合适的位置在什么地方呢?我认为,应当满足以下条件:
  1、setlocal和endlocal要配对使用:开启一次之后,再关闭;关闭之后,在进入for的下一次内部循环时,再开启一次,结束之时再关闭,但一定要保证开关的次数要对应;
  2、setlocal可以在for语句之前,也可以包含在for语句中,但是,一定要保证它们开关的次数要对应。
作者: namejm    时间: 2009-5-18 23:27

  尝试把if语句去掉,直接endlocal,发现代码也能正确执行,有点匪夷所思——我有点奇怪 "!#@#!"  的来历:为什么是这么一串突兀的字符串呢?能说说理由吗?
作者: netbenton    时间: 2009-5-18 23:28

测试过了,可以呀,
if "!#@#!" equ "" endlocal
是为了判断是否开启了变量延迟的(要保证不存在#@#变量)

我知道是要一一对应的,且可以在for 之前开启,在for内关闭,并不一定要在一个for内开就得在该for内关的,只要能做到一一对应就可以了。

在for前开,在for内关,有时会有意想不到的效果哦。
作者: netbenton    时间: 2009-5-18 23:31

re 14 楼
#@#是一个不存在的变量,如是开启了变量延迟,就会替换为空了,否则就是!#@#!
作者: namejm    时间: 2009-5-18 23:31

  在for前开,在for内关,开关的次数没有一一对应,竟然也不会出现“已达最大递归层”的错误,有点意外,我有点糊涂了,哪位来分析一下,说不定又会有新的突破^_^。
作者: 随风    时间: 2009-5-21 23:45     标题: 回复 17楼 的帖子

提示“最大递归层错误”是连续运行setlocal 32次,而非endlocal
其实12楼的代码完全可以取消if语句,直接endlocal就可以,不过感觉多余^_^
而且反复运行endlocal语句,始终感觉不太“健康”
  1. setlocal enabledelayedexpansion
  2. for %%a in ("!path:;=" "!") do (
  3.     endlocal
  4.     echo %%~a
  5. )
  6. pause
复制代码

作者: lovealei    时间: 2011-8-25 10:51

上面列出的内容可以输出到文本文件吗?




欢迎光临 批处理之家 (http://bbs.bathome.net/) Powered by Discuz! 7.2