Board logo

标题: [文本处理] [已解决]【随机排序】批处理标签中变量延迟失效的困惑 [打印本页]

作者: cjiabing    时间: 2011-8-19 18:09     标题: [已解决]【随机排序】批处理标签中变量延迟失效的困惑

以下是一个对文本进行随机排序的代码,但在代码之中,“echo %random% %%a”没有获得一个动态的随机数,而是变成了一个固定的数字。具体地说,我想用“!random!”获得动态时间,但发现“setlocal enabledelayedexpansion”已经失效。而且,这个标签开头还得额外加上“@echo off”,实在令人郁闷。诸位有写过变量函数的,是否曾经遇到过此问题,请求解释。
      以下去掉setlocal enabledelayedexpansion毫无大碍,但去掉标签中的@echo off则出现问题。似乎里面无法使用变量延迟。问题可能是我用括号将代码括起之后使用了sort,而直接调用会提示批脚本不能调用外部程序标签。
  1. @echo off
  2. call :sorttxt
  3. pause
  4. :SortTxt
  5. (@echo off
  6. for /f "tokens=*" %%a in (a.txt) do (
  7. setlocal enabledelayedexpansion
  8. echo %random% %%a
  9. endlocal
  10. )
  11. )|sort
  12. goto :eof
复制代码
==================================================
看来偷懒是不行的,下了决心去攻克,问题终于解决了。随机排序完整代码:
  1. @echo off
  2. ::把文本中的行(段落)打乱顺序,进行随机排序。用了一个cmd代替临时文件,用了两个for编辑。变量延迟方面稍有困难。
  3. call  :sorttxt     E:\Batch\test.txt
  4. pause
  5. exit
  6. :SortTxt
  7. for /f "tokens=1*" %%i in ('cmd /v:on /c "@echo off&for /f "usebackq tokens^=*" %%a in ("%1") do (echo ^!random^! %%a)"^|sort') do echo %%j
  8. goto :eof
复制代码

作者: CrLf    时间: 2011-8-19 18:31

管道惹的祸,管道有一个特性,当它所连接的内容中存在语块或内部命令时,将在新的 cmd 进程中执行这部分的命令,新 cmd 进程不属于脚本的一部分,它的运行环境类似于命令行窗口(和 bat 有所不同),其特性之一就是无法用 setlocal 开启本地化操作,而且也无法调用标签。
解决方案有两个,调用自身并获取输出、临时文件中转
作者: cjiabing    时间: 2011-8-19 19:47

晕,原来是这样。管道和sort的问题,确实如此,下午测试发现是这样的。但调用自身则无法使得该函数引用到其他程序中——这个我也试过了,如果使用临时文件则又不符合我用()|sort来取消临时文件的初衷。

想获得一个可以活得动态时间的代码的输出结果,放到一个For的集合中却又无法执行。

想重新开启变量延迟,我连call、cmd等都用过了,搞了一个下午都没搞定。帮忙看还有其他思路吗。
作者: cjiabing    时间: 2011-8-19 19:47

本帖最后由 cjiabing 于 2011-8-19 20:14 编辑

哈哈,又给我搞定了,还是用cmd,下午我可能搞得太复杂了。等下上得网再发代码。
作者: CrLf    时间: 2011-8-19 20:12

本帖最后由 CrLf 于 2011-8-19 20:14 编辑
  1. cmd /v /c for /f "delims==" %%a in ('set') do echo %%a:!%%a!|sort
复制代码

作者: cjiabing    时间: 2011-8-19 21:16

本帖最后由 cjiabing 于 2011-8-19 22:23 编辑

终于上得网了,该死的雨。谢谢CrLF。初步结果,文本随机排序,很简短:
  1. @echo off
  2. call  :sorttxt   E:\Batch\练习考试\屏蔽回显.txt
  3. pause
  4. exit
  5. :SortTxt
  6. for /f "tokens=1*" %%i in ('cmd /v:on /c "@echo off&for /f "usebackq tokens^=*" %%a in ("%1") do (echo !random! %%a)"^|sort') do echo %%j
  7. goto :eof
复制代码


::把文本中的行(段落)打乱顺序,进行随机排序。以前我通常会用findstr /n和临时文件,好傻。
::以下用了一个cmd代替临时文件,用了两个for编辑。
::但有一个致命伤,就是代码前不能用  setlocal enabledelayedexpansion 、endlocal、disenable……——求真相!~
::大家在使用代码测试的时候,要注意看代码运行后文本中的行是否变化了,变化了的是成功的,都都没有变化的是失败的。

::原因可能是你在开头使用了变量延迟。
作者: cjiabing    时间: 2011-8-19 22:11

谢谢CrLF!~一个“echo ^!random^! %%a”把变量延迟的问题解决了!~
作者: CrLf    时间: 2011-8-20 20:30

回复 6# cjiabing


    去请教了一下万能的寒夜版主,现在终于搞明白了,endlocal 必须和 setlocal 在一层中,call :test 就好比调用一个“子进程”,这个“子进程”继承了“父进程”的环境,但是本身并不存在 setlocal,所以在标签中 endlocal 只能和标签中的 setlocal 相互作用,做个试验就明白了:
  1. @echo off
  2. :test
  3. set /a n+=1
  4. echo %n%
  5. setlocal enabledelayedexpansion
  6. if %n%==33 echo setlocal 上限 32 层,若递归到 32 层以上仍不出错,则证明不同级的 setlocal 相互独立&pause
  7. call :test
复制代码
以前也没注意过,现在才知道有这回事...
作者: cjiabing    时间: 2011-8-20 23:36

回复 8# CrLf


    呵呵,见识了。从父进程继承了环境,而致使自身存在缺陷。




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