中国DOS联盟论坛

中国DOS联盟

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

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

游客:  注册 | 登录 | 命令行 | 会员 | 搜索 | 上传 | 帮助 »
中国DOS联盟论坛 » DOS批处理 & 脚本技术(批处理室) » [推荐][DOS]Assorted MS-DOS Batch Tricks(现征求译文)
作者:
标题: [推荐][DOS]Assorted MS-DOS Batch Tricks(现征求译文) 上一主题 | 下一主题
willsort
元老会员

Batchinger


积分 4432
发帖 1512
注册 2002-10-18
状态 离线
『楼 主』:  [推荐][DOS]Assorted MS-DOS Batch Tricks(现征求译文)

Assorted MS-DOS Batch Tricks                    Fri 11-November-2005
============================
                                                 All rights reserved
                               Copyright (c) 1993-2005 by Timo Salmi

....................................................................
Prof. Timo Salmi   Co-moderator of news:comp.archives.msdos.announce
Moderating at ftp:// & http://garbo.uwasa.fi/ archives 193.166.120.5
Department of Accounting and Business Finance  ; University of Vaasa
mailto:ts@uwasa.fi <http://www.uwasa.fi/~ts/>  ; FIN-65101,  Finland
Dense spam-kill procmail filtering with a public email key in effect
....................................................................

简介                                                                               
                                                                                   
  此文件包含了各式各样的批处理技巧,这些技巧条目并没有的特定的顺序,可能某
些条目会有许多重叠,也可能有很多条目没有用在压缩包中所附带的.bat文件中。同样
地 ,也有很多技巧用在那些.bat文件中,但却没有注明。
                                                                                   
  许多用户发给我一些很有用的建议和他们自己的选择以及进一步的解决办法,我很       
感谢他们提供这些材料。你能在 ftp://garbo.uwasa.fi/pc/pd2/tspost00.zip 文件中       
找到很多反馈和其他用户的解答。其他用户的解答部分列在tsbat.inf 的结尾。             
                                                                                   
Introduction                                                                       
============                                                                       
                                                                                   
This file contains assorted batch tricks. The items are in no                      
particular order. Also there is much overlap between some of the                   
items. Many, but not all the items, have been used in the .bat files               
included in the package. Likewise, there are some useful further                   
tricks, not documented in this particular file, to be found in the                 
batches included in the package.                                                   
                                                                                   
Many users have sent me useful suggestions and their own alternative               
or further solutions. My best thanks for the material. You can find                
much of this feedback and the other users' solutions stored in the                 
ftp://garbo.uwasa.fi/pc/pd2/tspost00.zip files. The items by the                   
other users are listed at the end of tsbat.inf included in this                    
collection.                                                                        



────────────── 版主提示 ──────────────
本主题仅允许回复附件中的涉及批处理技巧的译文和原文
对其中的某些批处理技巧的疑问和讨论请另发新主题,链接到本主题即可

本主题欢迎谙熟批处理和英语的达人襄助,并会酌情作出一定的积分奖励

为防止重复作业,请有意翻译者最好先回复主题预订你所要翻译的技巧
如要翻译多个技巧,请逐条回复预订,并在帖中标明待翻译技巧的编号和标题
预订截止期限暂定一周,一周内没有贴出技巧译文并未作说明的,将删除预订
完成翻译工作后,请编辑预订的回复帖,撤销预订并贴出译文和原文

一个回复仅限一篇技巧,包括原文和译文,但不要求回复顺序与技巧编号一致
回复帖标题格式:技巧编号.技巧标题中文
回复帖正文要求:译文在前,原文在后,文中代码除注释外均不译
────────────── 版主提示 ──────────────


相关下载:
联盟下载链接:http://cndos.l009.com/filedown/files/tsbat.zip
作者FTP链接:ftp://garbo.uwasa.fi/pc/link/tsbat.zip
附件下载链接如下:

[ Last edited by willsort on 2006-5-24 at 03:16 ]

附件 1: tsbat.zip (2006-5-17 21:57, 248.79 K, 下载附件所需积分 1 点 ,下载次数: 517)


※ Batchinger 致 Bat Fans:请访问 [讨论]批处理编程的异类 ,欢迎交流与共享批处理编程心得!
2006-5-17 21:49
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复
willsort
元老会员

Batchinger


积分 4432
发帖 1512
注册 2002-10-18
状态 离线
『第 2 楼』:  1.怎样使“@ECHO OFF”不依赖于MS-DOS的版本?

1.怎样使“@ECHO OFF”不依赖于MS-DOS的版本?
=========================================================
    如果你想关掉回显功能而不希望在屏幕上显示批处理命令行,可以使用 @echo off
来轻松实现。
    然而存在一个问题,因为这只能在 MS-DOS3.30 及其以后版本中使用。如果你想让
它更通用,可以在 autoexec.bat 文件中添加以下的行
      set _echo=@
    然后在你的批程序中使用下面的行,这样就可以使它在任何版本的 MS-DOS 中运行。
      %_echo%echo off
    当然,大多用户使用更新的版本。众所周知,独立发行的 MS-DOS 最终版本是6.22
,之后微软推出了 Windows 并试图结束 MS-DOS,而不管在全世界依然在使用它的大量
用户。
    如何获取 MS-DOS 的版本呢?当然是使用给定的命令 VER。在后面的第30号话题“
将 MS-DOS 的版本获取至环境变量中”中将会在批处理中使用到这个命令。
----------------------------------------------------------------------------

From ts@uwasa.fi Wed Apr 17 01:00:02 2002
Subject: Generalizing @echo off
Date: Wed, 17 Apr 2002 01:00:02
From: ts@uwasa.fi (Timo Salmi)

1. How can I make "@echo off" MS-DOS version independent?
=========================================================

If you want to turn the echo off, and do not wish to show that line
on the screen, you can easily do this by applying
@echo off
There is a catch, however, because this only works since MS-DOS
version 3.30. So if you want to make it general, put the following
line in your autoexec.bat file if you are using MS-DOS 3.30 or
higher
set _echo=@
Then use the following format in your batches, which will then work
for any MS-DOS version
%_echo%echo off

Of course, many if not most users will have a much more recent
MS-DOS version. As we know, the last released independent MS-DOS is
6.22. After that Microsoft has been pushing Windows and trying to
kill its MS-DOS despite the huge user base still left in the world.
   How does one find out which MS-DOS version one has? The version
is, of course, given by the VER command. For using this in testing
in a batch see the later item #30 "How to obtain the MS-DOS version
into an environment variable?"
--------------------------------------------------------------------

译者注:

    第一次翻译一些英文文献,兼且本人英语水平实在粗浅,不免疏漏众多,忝颜贴出,
敬请方家指教。若有疑问、意见或建议还请另发新主题,不便之处尚请海涵!

    这应该算是一个相当古老的技巧了,但是它仍然讨论到了2002年,可见其生命力之
顽强。

    因为在MS-DOS3.30以下版本的系统中,不支持命令单行回显禁止符“@ ”,为了让
我们编写的批处理代码可以在这些系统中正常运行,我们需要考虑用环境变量来根据系
统版本来决定是否启用“@ ”。

    当然这种判断是由用户来做出的,也就是说MS-DOS3.30及其以上版本的用户需要自
行设置变量_echo ,而以前版本的用户则什么也不用做。现在来看这种做法,实在是有
些不公,毕竟“新版本”的用户远远多于“老版本”的用户,所谓多数迁就少数,未免
说不过去。

    现在的批处理基本上已经不考虑这个技巧的使用了。但与相关的还有另外一个技巧,
那是关于如何方便地调试批处理程序。

    我们知道在一个批处理程序尤其是较复杂的程序编写完成之前,必须经过反复多次
的调试和修改。在调试过程中,我们十分有必要知道程序的运行流程,此时我们就需要
撤销命令行回显的屏蔽语句@echo off 。

    通常我们的做法是,删除这一行或者用rem 或者::注释这一行,而当我们的调试经
过一个阶段后,我们需要重新恢复命令行回显的屏蔽,以观察程序的正常运行状态,此
时我们又需要重写这一行或者去处rem 或者::的注释标记。

    这样没什么不好,只是那是在调试工作比较顺利的时候。而我们恰好遇到了一个非
常挠头的程序,经过反复调试和修改总也无法正常运行,那么就需要无数次的打开批处
理、编辑批处理、保存批处理、运行批处理……,如此循环往复,直到我们对批处理编
程的兴趣丧失殆尽。

    然而,有一个技巧可以解决这个问题。只要我们将 @echo off改写成 @echo %dbg%
off ,这样我们就再也不用为调试批处理而频繁进出编辑器了。如果我们要调试批处理,
只需要在命令行下键入 set dbg=on ;而如果我们要正常地运行它,则再键入 set dbg=
即可。

    原理简述:当 dbg=on 时, @echo %dbg% off为 @echo on off ,命令行回显状态
被开启;当 dbg= 时,@echo %dbg% off 为 @echo off,命令行回显状态被关闭。

    道理就是如此简单,实在没什么好奇怪的。


[ Last edited by willsort on 2006-5-24 at 04:27 ]

   此帖被 +1 点积分     点击查看详情   
评分人:【 redtek 分数: +1  时间:2006-11-15 02:55




※ Batchinger 致 Bat Fans:请访问 [讨论]批处理编程的异类 ,欢迎交流与共享批处理编程心得!
2006-5-18 14:01
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复
willsort
元老会员

Batchinger


积分 4432
发帖 1512
注册 2002-10-18
状态 离线
『第 3 楼』:  2.不加提示删除所有文件


2.不加提示删除所有文件
============================================
    关于批处理最频繁提出的问题(FAQ)之一是如何屏蔽执行del *.* 命令时的确
认请求“Are you sure (Y/N)?”,可以使用以下用法:
      echo y| del *.*
    如果你也想屏蔽提示信息,请使用
      echo y| del *.* > nul
    此外还有另一个选择
      for %%f in (*.*) do del %%f
    如果目录是空的,要避免“文件未找到”的信息,可用
      if exist *.* echo y| del *.* > nul
    一个更好的也显而易见的修改来自 Rik D'haveloose
      if exist *.* for %%f in (*.*) do del %%f

    尽管屏蔽确认信息是否明智尚在争议之中,但不管怎样,这些技巧已经存在。更危
险的是在诸如 DELTREE或 FORMAT 此类的命令中使用此技巧,我并不推荐如此使用。事
实上,取缔这两个命令会更好(使用他们应该需要完整的路径,如同在 1DOSTRIK.TXT
条目7“已选定的 Doskey 宏命令”给出的示例)。替代的方法是将它们移动到一个不
在搜索路径的隐藏目录中。(使目录隐藏参见“HELP ATTRIB”)
----------------------------------------------------------------------------

From ts@uwasa.fi Wed Apr 17 01:00:03 2002
Subject: Deleting all files
Date: Wed, 17 Apr 2002 01:00:03
From: ts@uwasa.fi (Timo Salmi)

2. Deleting all files without being prompted
============================================

One of the most Frequently Asked Questions (FAQs) about batches is
how to suppress the "Are you sure (Y/N)?" confirmation requirement
for del *.*.  Use the following:
echo y| del *.*
If you wish to suppress the message too, use
echo y| del *.* > nul
There is also another alternative for doing this:
for %%f in (*.*) do del %%f
If the directory is empty you can avoid the "File not found" message
by applying
if exist *.* echo y| del *.* > nul
A better, obvious alternative by Rik D'haveloose:
  if exist *.* for %%f in (*.*) do del %%f

Whether or not it is sensible to suppress the confirmation can be
debated, but these are the tricks anyway. Even more dangerous is
using such a trick on DELTREE or FORMAT. I do not recommend it. In
fact it is better to disable these two commands (so that they will
require a full path, as given in 1DOSTRIK.TXT item "7. Selected
Doskey macro examples". Or, alternatively, one can move them to a
hidden directory, out of the path. (See HELP ATTRIB for making a
dirctory hidden.)
--------------------------------------------------------------------

译者注:

    尽管我对前辈怀有十二分的崇敬,但我仍然希望可以证明技术是不断进步的。

    例如,在文中的最后一个修改中提到
        if exist *.* for %%f in (*.*) do del %%f

    但是,我的经验告诉我,在此句中if exist *.*是不必要的。所以,在我的批处理
中,删除批处理程序产生的临时文件时常常采用:
        for %%f in (_%0*.* ~%0*.* *.tmp) do del %%f
   
    而不会选用这种方法:
        if exist _%0*.* for %%f in (_%0*.*) do del %%f
        if exist ~%0*.* for %%f in (~%0*.*) do del %%f
        if exist *.tmp for %%f in (*.tmp) do del %%f
   
    或者这种方法:
        for %%f in (_%0*.* ~%0*.* *.tmp) do if exist %%f del %%f
   
    如果删除的文件是许多个名字杂乱无法进行通配的文件,我也会使用:
        for %%f in (src.tmp* dst.dat* _media.bat*) do del %%f
   
    而不会选用:
        if exist src.tmp del src.tmp
        if exist dst.dat del dst.dat
        if exist _media.bat del dst.bat
   
    或者:
        for %%f in (src.tmp dst.dat _media.bat) do if exist %%f del %%f
        
    这一切只是因为,如果在for 的可替换集(括号中的部分)中使用了通配符,就会
将其中的文本串作为文件名的集合进行替换,替换前会搜索所有匹配这个通配符的文件
,而能够搜索到的文件,毫无疑问都是存在的。


[ Last edited by willsort on 2006-5-31 at 11:16 ]

   此帖被 +1 点积分     点击查看详情   
评分人:【 redtek 分数: +1  时间:2006-11-15 02:58




※ Batchinger 致 Bat Fans:请访问 [讨论]批处理编程的异类 ,欢迎交流与共享批处理编程心得!
2006-5-18 14:03
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复
willsort
元老会员

Batchinger


积分 4432
发帖 1512
注册 2002-10-18
状态 离线
『第 4 楼』:  3.在批处理中可以嵌套使用for循环吗?


3.在批处理中可以嵌套使用for循环吗?
===================================================
    是的,在批处理编程中使用嵌套循环是可行的,但是不能直接使用,你需要调用
第二个批处理文件。请参考以下两个批处理,并可以调用 TEST.BAT 来试一试。

      @echo off
      rem TEST.BAT
      for %%f in (a b c d e f) do %comspec% /c test2 %%f
   
      @echo off
      rem TEST2.BAT
      echo.
      for %%g in (1 2 3) do echo %1%%g

    上面使用了 %COMSPEC%,在 MS-DOS 各种版本间它具有更大的普遍性。另外,你可
以稍做修改。

      @echo off
      rem TEST.BAT
      for %%f in (a b c d e f) do call test2 %%f

    TEST2.BAT 的“echo.”一行只为使它的输出有更佳的可读性。
    也可以仅使用一个批处理文件,用第一个批处理创建第二个批处理的方法。

      @echo off
      rem TEST.BAT
      ::
      echo @echo off > test$$$2.bat
      echo echo. >> test$$$2.bat
      echo for %%%%g in (1 2 3) do echo %%1%%%%g >> test$$$2.bat
      ::
      for %%f in (a b c d e f) do call test$$$2 %%f
      if exist test$$$2.bat del test$$$2.bat

    注意使用 ECHO 从一个批处理文件向另一个批处理文件回显时额外的"%"
    另一个选择是在一行里写上所有的内容,如下:

      for %%f in (a b c d e f) do %comspec% /c
        for %%g in (1 2 3) do echo %%f%%g

    文字中的换行是因为右边界的限制,在你的批处理中是不能换行的。这个方法
的缺点是回显开关将被打开。

    你可能因为把 CALL 替换为 %COMSPEC% /C 而惊讶。实际上,COMSPEC 是一个环境
变量,它指出了命令解释器COMMAND.COM 的位置。而 /C 开关告诉命令解释器,运行完
指定行内容后退出。 /C 开关必须是命令行上的最后一个开关。 %COMSPEC% /C 的修订
可用于没有CALL命令的MS-DOS早期版本中。

    其它的选择是使用第三方程序或者利用类似 G(nu)Awk 的 unix 接口。以下是基于
awk 的解决方案。

      @echo off
      ::
      :: Initialize and run the outer loop from 1 to 5.
      set i_=0
      :_loop
        echo %i_%|gawk '{printf "@set i_=%%s\n",$1+=1}'>tmp###.bat
        call tmp###.bat
        :: The inner loop with a for loop (could be "gawked", as well)
        for %%f in (1 2 3) do echo %i_% %%f
      if "%i_%"=="5" goto _out
      goto _loop
      ::
      :: Clean up
      :_out
      set i_=
      for %%f in (tmp###.bat) do if exist %%f del %%f

    在 GAWK 编写的方案中,下面这一个写起来相对容易一些

      @echo off
      >  tmp$$$.awk echo {
      >> tmp$$$.awk echo for (i=1;i!=6;i++)
      >> tmp$$$.awk echo   for (j=1;j!=4;j++)
      >> tmp$$$.awk echo     printf "i=%%s j=%%s\n",i,j
      >> tmp$$$.awk echo }
      ::
      echo.|gawk -f tmp$$$.awk
      ::
      for %%f in (tmp$$$.awk) do if exist %%f del %%f

    使用递归调用的嵌套循环对于某些任务来说是有用的。请考虑一个不断显示数字1
到99的问题示例。下面给出了问题的答案。如果你希望从00而不是01开始,那么
删除这一行:if "%x_%"=="00" goto _out 。格式来源于 Herbert Kleebauer的感谢信,
但是最初的想法至少可以追溯到 John Savage的一封信 "标题:小说计数器, 日期:
1996/07/03 消息ID: <4rdq1s$5uo$1@sydney.DIALix.oz.au>."

      @echo off
      if not "%2"=="" goto _subru
      for %%i in (0 1 2 3 4 5 6 7 8 9) do call %0 %1 %%i
      goto _out
      :_subru
      set x_=%1%2
      if "%x_%"=="00" goto _out
      echo %x_%
      :_out

    另一个问题,如果你想从000循环到255该怎么办?

      @echo off
      if "%exit_%"=="yes" goto _out
      if not "%3"=="" goto _subru
      for %%i in (0 1 2 3 4 5 6 7 8 9) do call %0 %1 %2 %%i
      goto _out
      :_subru
      set x_=%1%2%3
      echo %x_%
      if "%x_%"=="255" set exit_=yes
      :_out

    还有另一个方法在批程序中建立嵌套的循环,这一次用不到一个“FOR”

      @echo off
      ::
      :: Initialize
      set i_=0
      :: The outer loop (run from 1 to 5)
      :_loop_i
        ::
        :: Use FN.EXE
        :: to increase the variable
        fn /e %i_%+1 0 > nul
        set i_=%fn_%
        ::
        :: The inner loop (run from 1 to 3)
        set j_=0
        :_loop_j
          fn /e %j_%+1 0 > nul
          set j_=%fn_%
          :: Perform whatever
          echo i_=%i_% j_=%j_%
          ::
          if "%j_%"=="3" goto _next_i
        goto _loop_j
      :_next_i
      if "%i_%"=="5" goto _end_i
      goto _loop_i
      :_end_i
      ::
      :: Clean up
      for %%v in (i_ j_ fn_) do set %%v=

    根据以上方法,一个用于 Herbert's 技巧的可选方案是这样的

      @echo off
      :: Initialize
      set i_=-1
      set z_=00%  Set leading zeroes%
      :_loop_i
        ::
        :: Use FN.EXE
        :: to increase the variable
        fn /e %i_%+1 0 > nul
        set i_=%fn_%
        if "%i_%"=="10" set z_=0
        if "%i_%"=="100" set z_=
        echo %z_%%i_%
      :_next_i
      if "%i_%"=="255" goto _end_i
      goto _loop_i
      :_end_i
      ::
      :: Clean up
      for %%v in (i_ z_ fn_) do set %%v=
----------------------------------------------------------------------------

From ts@uwasa.fi Wed Apr 17 01:00:04 2002
Subject: Nested for loops
Date: Wed, 17 Apr 2002 01:00:04
From: ts@uwasa.fi (Timo Salmi)

3. Is it possible to nest for loops in batch files?
===================================================

Yes, it is possible to have nested loops of a kind in batch
programming, but not directly. You have to call a second batch file.
Consider the following two batches, and try it out by calling
test.bat.
  @echo off
  rem TEST.BAT
  for %%f in (a b c d e f) do %comspec% /c test2 %%f

  @echo off
  rem TEST2.BAT
  echo.
  for %%g in (1 2 3) do echo %1%%g

   In the above "%comspec%" has been used for greater generality
across MS-DOS versions. Alternatively you could have
  @echo off
  rem TEST.BAT
  for %%f in (a b c d e f) do call test2 %%f

   In TEST2.BAT the line "echo." is only for better readability of the
output.
   It is also possible to use only one batch file by letting the
first batch create the second

  @echo off
  rem TEST.BAT
  ::
  echo @echo off > test$$$2.bat
  echo echo. >> test$$$2.bat
  echo for %%%%g in (1 2 3) do echo %%1%%%%g >> test$$$2.bat
  ::
  for %%f in (a b c d e f) do call test$$$2 %%f
  if exist test$$$2.bat del test$$$2.bat

Note the need of the extra "%":s in echoing from a batch file to
another.
Another alternative is to write everything as below on a *SINGLE*
line:
  for %%f in (a b c d e f) do %comspec% /c
    for %%g in (1 2 3) do echo %%f%%g
(The wrap has been used in the text is because of the right margin.
Don't wrap your batch.). The disadvantage of this alternative is
that the echo will be on.
In the above you may wonder about the "%COMSPEC% /C" alternative to
"CALL". The comspec is and environment variable that points to the
location of the COMMAND.COM command interpreter. The /C switch tells
that the command interpreter is to exit after performing the
specified line. The /C switch must be the last switch on the command
line. The "%COMSPEC% /C" alternative is available in earlier
versions of MS-DOS than the CALL command.
Another option is to use third party programs and utilize a unix
port like G(nu)Awk. Below is an awk-based solution
  @echo off
  ::
  :: Initialize and run the outer loop from 1 to 5.
  set i_=0
  :_loop
    echo %i_%|gawk '{printf "@set i_=%%s\n",$1+=1}'>tmp###.bat
    call tmp###.bat
    :: The inner loop with a for loop (could be "gawked", as well)
    for %%f in (1 2 3) do echo %i_% %%f
  if "%i_%"=="5" goto _out
  goto _loop
  ::
  :: Clean up
  :_out
  set i_=
  for %%f in (tmp###.bat) do if exist %%f del %%f
Within GAWK programming solutions like the one below are relatively
easy to write:
  @echo off
  >  tmp$$$.awk echo {
  >> tmp$$$.awk echo for (i=1;i!=6;i++)
  >> tmp$$$.awk echo   for (j=1;j!=4;j++)
  >> tmp$$$.awk echo     printf "i=%%s j=%%s\n",i,j
  >> tmp$$$.awk echo }
  ::
  echo.|gawk -f tmp$$$.awk
  ::
  for %%f in (tmp$$$.awk) do if exist %%f del %%f

A nested loop using recursive calling is useful for several tasks.
Consider an example problem of echoing sequentially the numbers from
01 to 99. The solution is given below. If you wish to start from
"00" rather than "01", then delete the line: if "%x_%"=="00" goto
_out. The format initiates from an appreciated posting by Herbert
Kleebauer but the initial idea dates back at least to John Savage
"Subject: a novel counter, Date: 1996/07/03 Message-ID:
<4rdq1s$5uo$1@sydney.DIALix.oz.au>."
  @echo off
  if not "%2"=="" goto _subru
  for %%i in (0 1 2 3 4 5 6 7 8 9) do call %0 %1 %%i
  goto _out
  :_subru
  set x_=%1%2
  if "%x_%"=="00" goto _out
  echo %x_%
  :_out
Another case. What if you want a loop from "000" to "255"?
  @echo off
  if "%exit_%"=="yes" goto _out
  if not "%3"=="" goto _subru
  for %%i in (0 1 2 3 4 5 6 7 8 9) do call %0 %1 %2 %%i
  goto _out
  :_subru
  set x_=%1%2%3
  echo %x_%
  if "%x_%"=="255" set exit_=yes
  :_out
Yet another method and example to build nested loops in batches.
This time without any 'for's
  @echo off
  ::
  :: Initialize
  set i_=0
  :: The outer loop (run from 1 to 5)
  :_loop_i
    ::
    :: Use FN.EXE
    :: to increase the variable
    fn /e %i_%+1 0 > nul
    set i_=%fn_%
    ::
    :: The inner loop (run from 1 to 3)
    set j_=0
    :_loop_j
      fn /e %j_%+1 0 > nul
      set j_=%fn_%
      :: Perform whatever
      echo i_=%i_% j_=%j_%
      ::
      if "%j_%"=="3" goto _next_i
    goto _loop_j
  :_next_i
  if "%i_%"=="5" goto _end_i
  goto _loop_i
  :_end_i
  ::
  :: Clean up
  for %%v in (i_ j_ fn_) do set %%v=
With the above method, an alternative solution to Herbert's trick
would be
  @echo off
  :: Initialize
  set i_=-1
  set z_=00%  Set leading zeroes%
  :_loop_i
    ::
    :: Use FN.EXE
    :: to increase the variable
    fn /e %i_%+1 0 > nul
    set i_=%fn_%
    if "%i_%"=="10" set z_=0
    if "%i_%"=="100" set z_=
    echo %z_%%i_%
  :_next_i
  if "%i_%"=="255" goto _end_i
  goto _loop_i
  :_end_i
  ::
  :: Clean up
  for %%v in (i_ z_ fn_) do set %%v=
--------------------------------------------------------------------
译者注:

  如果可能,我不会愿意将“译者注”成为我的译文的一部分,毕竟你我的时间都是
宝贵的。不过我记忆深处的一根弦又一次被触动了。

  下面的代码转贴自本论坛,它只是一个用于算法演示的原型,存在许多缺陷,要想
真正应用还有许多细节需要修订。如果你有兴趣了解详细的情形,请参阅[1] 。在此仅
简单介绍一下批处理中的另一种不使用for 的循环实现方式——命令行参数循环。

@echo off
if not [%1]==[] goto loop
call %0 d e f g h i j k l m n o p q r s t u v w x y z
goto end

:loop
if %1#==# goto end
if exist %1:\target.txt dir %1:\target.txt
if exist %1:\target.txt type %1:\target.txt
shift
goto loop

:end

  以上的代码中,call %0 一句代替 for in ()用来控制循环的范围,if not [%1]
一句代替 do 指示循环主体代码的位置,:loop 实现的则是需要反复运行的循环主体。
shift 实现循环变量的递增,goto loop 用于继续下一轮循环,if %1#==# 则控制循环
是否已经结束。因此,我们是用批处理代码模拟了类似于汇编代码的循环语句。

  那么,我们为什么要将简单的循环复杂而低级的实现呢?因为我们要利用命令行中
“参数指针框”。

  例如,我们在for 循环中可以使用%%i 来引用循环变量的当前值,但有时我们不仅
仅需要知道当前值,而可能还需要了解前几次循环中曾经出现过的值或者下几次循环中
将要出现的值。然而,for 只给我们提供了一个指针变量,它只指向当前循环中的值。

  而能够在同一时刻指向多个值的指针变量是存在的,那就是命令行参数,用上面的
话说,就是“参数指针框”,在这个框内总是同时囊括了前后形关的十个变量,可通过
%0,%1...%9来单独或同时引用它们的值。

  下面的代码就恰恰使用了“参数指针框”的特性。它同样转贴自本论坛,详细的情
形请参阅[2] 。

@echo off
if [%1]==[] call %0 1 2 3 4 5 6 7 8 9

:loop
if [%2]==[] goto end
echo %1>%2.txt
shift
goto loop

:end

    可以看到,我们在:loop 中同时使用了%1和%2,也就是说,我们同时引用了循环变
量的当前值和上一次值,这使得我们可以将字符1 写到文件2.txt中,将2 写到3.txt中,
如此直至循环结束。

    使用命令行参数循环还有其它的优点:它可以使循环变量一次循环后跨越多个值,
对于类似"姓名 性别 年龄 张三 男 23 李思 女 21"的数据库记录读取中,它很有用;
它可以随时终止循环或者直接跳到下一次循环,类似C 语言的break 和continue语句;
它比"for in () do call" 的形式具有更高的效率,因为整个循环过程中,前者只需要
读取一次批处理程序自身文件,而后者则每一次循环均要读取文件。

    更多的技巧,散落在论坛中无人注意的角落,只要有心,你就会有所收获。

[1]征求怎样简化DOS批处理的交互式问答??
http://www.cn-dos.net/forum/viewthread.php?tid=9090

[2]将数字 1 写入 2.txt 文件 2写入3.txt 类推
http://www.cn-dos.net/forum/viewthread.php?tid=14552


[ Last edited by willsort on 2006-5-31 at 11:15 ]

   此帖被 +1 点积分     点击查看详情   
评分人:【 redtek 分数: +1  时间:2006-11-15 02:58




※ Batchinger 致 Bat Fans:请访问 [讨论]批处理编程的异类 ,欢迎交流与共享批处理编程心得!
2006-5-24 04:31
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复
willsort
元老会员

Batchinger


积分 4432
发帖 1512
注册 2002-10-18
状态 离线
『第 5 楼』:  4.怎样检查一个目录是否存在?


4.怎样检查一个目录是否存在?
=========================================================
    有时检测一个特定目录的存在是很有用的,下面的测试中如果目录 %1 不存在,那
么结果为真。
      if not exist %1\nul if not exist %1nul echo Directory %1 does not exist
    然而,这个方法似乎不能在 CD-ROM 中使用,可能是因为 CD-ROM 驱动器使用了一
种不同的文件系统,它没有. 与..,因而更紧凑。感谢 Bjorn Svensson 让我获悉一个
在 CD-ROM 中也能正常运行的方案。
      @echo off
      if "%1"=="" goto _usage
      set target_=%1
      ctty nul
      dir /ad  %target_% | find " file(s) "
      ctty con
      if errorlevel==2 goto _1
      if errorlevel==1 goto _1
      echo Directory %target_% exists
      goto _out
      :_1
      echo Directory %target_% does not exist
      goto _out
      :_usage
      echo Usage %0 DirectoryName
      :_out
      set target_=
    如果目录不存在,成对命令 CTTY NUL/CTTY CON 可以禁止显示 File not found
的错误信息。值得注意的是,应该正确使用 CTTY NUL/CTTY CON 命令对,以免锁死你
的系统。
    我自己检测目录的存在则使用自己设计的另外一个非常简单的方法。
      @echo off
      ::
      if "%1"=="" goto _usage
      ::
      dir %1|find " Directory of "|find /i "%1">nul
      set found_=yes
      if errorlevel==2 set found_=no
      if errorlevel==1 set found_=no
      ::
      if "%found_%"=="yes" echo %1 is a directory
      if "%found_%"=="no" echo %1 is not a directory
      goto _end
      ::
      :_usage
      echo Usage: %0 [Target]
      ::
      :_end
      set found_=
    还可以更完整一点,测试目标是目录、文件还是不存在
      @echo off
      ::
      if "%1"=="" goto _usage
      ::
      ctty nul
      dir %1|find " Directory of "|find /i "%1">nul
      ctty con
      set found_=yes
      if errorlevel==2 set found_=no
      if errorlevel==1 set found_=no
      ::
      if not "%found_%"=="yes" goto _not
      echo %1 is a directory
      goto _end
      ::
      :_not
      echo %1 is not a directory
      if exist %1 echo However %1 is a file
      if not exist %1 echo Nor is %1 a file
      ::
      goto _end
      ::
      :_usage
      echo Usage: %0 [Target]
      ::
      :_end
      set found_=

    此外,在 Windows的 DOS窗口中或者 Windows的 MS-DOS 版本中使用方法 if not
exist %1\nul会导致一些问题。尽管这个FAQ 类的文件是为纯正的 MS-DOS 而写的,但
是仍然有不依赖 \nul 技巧的其它选择。其中一个就是尝试向目标中写一个文件,然后
检测文件是否存在。很显然,这个技巧不能用于类似光盘和写保护磁盘的只读设备。但
另一方面,如果你的意图是想往目录中写某些东西,那么这个技巧恰巧有用。
      @echo off
      if "%1"=="" goto _help
      ctty nul
      echo.>%1\tmp#$#$#
      ctty con
      if exist %1\tmp#$#$# echo Directory %1\ exists
      if not exist %1\tmp#$#$# echo Directory %1\ does not exist
      if exist %1\tmp#$#$# del %1\tmp#$#$#
      goto _end
      :_help
      echo Usage %0 [DirectoryName]
      echo No backslash. Root e.g. as C:
      echo A subdirectory e.g. as C:\TMP
      :_end
----------------------------------------------------------------------------

From ts@uwasa.fi Wed Apr 17 01:00:05 2002
Subject: Checking directory existence
Date: Wed, 17 Apr 2002 01:00:05
From: ts@uwasa.fi (Timo Salmi)

4. How can I check in a batch whether a directory exists?
=========================================================
It is sometimes useful to be able to test whether a particular
directory exists. The following test is true if the %1 directory
does not exist.
if not exist %1\nul if not exist %1nul echo Directory %1 does not exist

However, this does not seem to work for a CD-ROM. Probably because
of the CD-ROM drivers use a slightly different directory system with
no . (dot) and .. (dot-dot). My thanks to Bjorn Svensson for
bringing this to my attention. A solution that works also for
CR-ROMs is
  @echo off
  if "%1"=="" goto _usage
  set target_=%1
  ctty nul
  dir /ad  %target_% | find " file(s) "
  if errorlevel==2 goto _1
  if errorlevel==1 goto _1
  echo Directory %target_% exists
  goto _out
  :_1
  echo Directory %target_% does not exist
  goto _out
  :_usage
  echo Usage %0 DirectoryName
  :_out
  set target_=
The "ctty nul/ctty con" command pair suppresses displaying the "File
not found" error message if the directory does not exist. Be careful
to get the "ctty nul/ctty con" pair right lest you lock your system.

Another, very similar but independently developed method of my own
(un)doing for testing directory existence
  @echo off
  ::
  if "%1"=="" goto _usage
  ::
  dir %1|find " Directory of "|find /i "%1">nul
  set found_=yes
  if errorlevel==2 set found_=no
  if errorlevel==1 set found_=no
  ::
  if "%found_%"=="yes" echo %1 is a directory
  if "%found_%"=="no" echo %1 is not a directory
  goto _end
  ::
  :_usage
  echo Usage: %0 [Target]
  ::
  :_end
  set found_=
Or, a bit more completely, to test if the target is a directory,
file or does not exist.
  @echo off
  ::
  if "%1"=="" goto _usage
  ::
  ctty nul
  dir %1|find " Directory of "|find /i "%1">nul
  ctty con
  set found_=yes
  if errorlevel==2 set found_=no
  if errorlevel==1 set found_=no
  ::
  if not "%found_%"=="yes" goto _not
  echo %1 is a directory
  goto _end
  ::
  :_not
  echo %1 is not a directory
  if exist %1 echo However %1 is a file
  if not exist %1 echo Nor is %1 a file
  ::
  goto _end
  ::
  :_usage
  echo Usage: %0 [Target]
  ::
  :_end
  set found_=
Furthermore in the "if not exist %1\nul" method problems are caused
by the Windows dosbox / MS-DOS versions for Windows. Although this
FAQ-type file has been written for vanilla MS-DOS let's consider yet
another alternative that does not rely on the \nul trick. One way of
testing the existence of a directory is trying to write a file to
it, and testing if the file then exists. Obviously this trick can't
be used for read-only devices like CD-ROMs and write protected
diskettes. On the other hand exactly that is the usefulness of this
method if the intention is to write something.
  @echo off
  if "%1"=="" goto _help
  ctty nul
  echo.>%1\tmp#$#$#
  ctty con
  if exist %1\tmp#$#$# echo Directory %1\ exists
  if not exist %1\tmp#$#$# echo Directory %1\ does not exist
  if exist %1\tmp#$#$# del %1\tmp#$#$#
  goto _end
  :_help
  echo Usage %0 [DirectoryName]
  echo No backslash. Root e.g. as C:
  echo A subdirectory e.g. as C:\TMP
  :_end
--------------------------------------------------------------------
译者注:

    不得不承认,再驯良的骏马也有失前蹄的时候,再严谨的专家也会有出错的时候。
   
    在原文的第二段代码(就是第一个可以在 CD-ROM 中使用的方案)中,dir 一句后
没有见到与ctty nul相对应的ctty con语句,而其下的说明文字中却还特意提到“应该
应该正确使用 CTTY NUL/CTTY CON命令对”。

    当然,在译文中,这个错误已经被纠正了。
   
    另外,还需要再次提醒各位读者的是,这里所提到的所有技巧都是为纯粹的MS-DOS
所设计的,他们中有些部分在后来的Windows 命令行中已不再有用,有些虽然有用,但
已不是最有用的。

    例如,在WindowsXP 中的CMD 环境中,内部命令ctty已不再支持,这很大程度上是
因为它不再有用。禁止命令输出错误信息,可以在命令行之后加上2>nul ;而要判断目
录是否存在,只要使用 if exist %1\ 就足够了。

    当然,如果你是想让你的程序在各种命令行下都可以正常运行,那么你需要考虑很
多的问题。在此之前,建议首先参考以下的链接,以确定你是否真要实现可以“兼容”
各个命令行环境的程序。

[1][讨论]批处理编程的异类-目录的存在判定
http://www.cn-dos.net/forum/viewthread.php?tid=12388#pid100421

[2] 如何判断参数是文件还是目录
http://www.cn-dos.net/forum/viewthread.php?tid=20999

[3]如何判断谋个盘符下谋个文件夹是否存在???[求助]
http://www.cn-dos.net/forum/viewthread.php?tid=686


[ Last edited by willsort on 2006-6-6 at 21:29 ]

   此帖被 +5 点积分       点击查看详情   
评分人:【 redtek 分数: +5  时间:2006-11-15 02:59




※ Batchinger 致 Bat Fans:请访问 [讨论]批处理编程的异类 ,欢迎交流与共享批处理编程心得!
2006-5-31 03:37
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复
3742668
荣誉版主





积分 2013
发帖 718
注册 2006-2-18
状态 离线
『第 6 楼』:  

为了让更多的朋友看到本贴,也不忍看到willsort的心血就这么沉下去,俺就暂时把这个贴置顶吧。另外建议willsort把那个cmd下的求译文的贴子和这个合并到顶楼吧,置顶贴太多了也不好,不知兄意下如何。
    可能是曲高和寡吧,看来willsort注定是一个孤独的人。本来准备努力尝试也来两篇cmd下的译文的,不过由于E文实在是烂(接近初中水平?),加上对cmd部分中的bat与vbs一把抓感觉不是很爽(bat调用vbs不如全部交给vbs去做),更重要的是我看E文的文章是根据代码去猜E文的内容,而且看完后并不能似willsort这般来两段比较高明的译者注,所以一直没有什么东东贴出来。

2006-5-31 21:01
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复
willsort
元老会员

Batchinger


积分 4432
发帖 1512
注册 2002-10-18
状态 离线
『第 7 楼』:  

预订:
5.检测一个程序是否在当前目录或者 PATH 中可用
5. Checking that a program is available at the current directory or at path

Re 3742668:

      感谢兄的肯定与置顶。

      尽管我认为,相比置顶而言,不断回复可以更有效地提高它的访问率,但是开放非译文回复,仍然不是我所乐见的,因为它会干扰主题的秩序。与tscmd合并就更加困难了。

      如果有人确实需要进行相关的回复,我建议他如我一样,首先预订一个翻译序号,然后在预订帖中添加回复。如果确无时间或精力翻译,可以在一周之后自行删除预订帖。

  Quote:
为了让更多的朋友看到本贴,也不忍看到willsort的心血就这么沉下去,俺就暂时把这个贴置顶吧。另外建议willsort把那个cmd下的求译文的贴子和这个合并到顶楼吧,置顶贴太多了也不好,不知兄意下如何。
    可能是曲高和寡吧,看来willsort注定是一个孤独的人。本来准备努力尝试也来两篇cmd下的译文的,不过由于E文实在是烂(接近初中水平?),加上对cmd部分中的bat与vbs一把抓感觉不是很爽(bat调用vbs不如全部交给vbs去做),更重要的是我看E文的文章是根据代码去猜E文的内容,而且看完后并不能似willsort这般来两段比较高明的译者注,所以一直没有什么东东贴出来。

[ Last edited by willsort on 2006-6-6 at 21:40 ]



※ Batchinger 致 Bat Fans:请访问 [讨论]批处理编程的异类 ,欢迎交流与共享批处理编程心得!
2006-6-6 21:31
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复
qylml
新手上路





积分 10
发帖 5
注册 2006-6-13
状态 离线
『第 8 楼』:  

呵呵,最近刚开始学批处理脚本,也是十分喜欢。好容易找到这个论坛来了,真的学到好多东西。谢谢分享!!!

2006-6-13 12:55
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复
xiongwei2624
初级用户





积分 96
发帖 44
注册 2006-6-26
来自 深圳
状态 离线
『第 9 楼』:  

感谢,还是有许多不是很懂慢慢学!!

2006-6-27 15:19
查看资料  发送邮件  访问主页  发短消息 网志  OICQ (3099591)  编辑帖子  回复  引用回复
xiaojun
银牌会员





积分 2202
发帖 499
注册 2003-6-12
状态 离线
『第 10 楼』:  

好帖,收藏

[ Last edited by xiaojun on 2006-7-7 at 23:47 ]



一年四季,枫叶红了又红;人生四季,失去的,还能再来吗?—— !
2006-7-7 23:25
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复
electronixtar
铂金会员





积分 7493
发帖 2672
注册 2005-9-2
状态 离线
『第 11 楼』:  

好帖子不要沉了!




C:\>BLOG http://initiative.yo2.cn/
C:\>hh.exe ntcmds.chm::/ntcmds.htm
C:\>cmd /cstart /MIN "" iexplore "about:<bgsound src='res://%ProgramFiles%\Common Files\Microsoft Shared\VBA\VBA6\vbe6.dll/10/5432'>"
2006-11-15 01:22
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复
ccwan
金牌会员




积分 2725
发帖 1160
注册 2006-9-23
来自 河北廊坊
状态 离线
『第 12 楼』:  

崇拜ing



三人行,必有吾师焉。   学然后知不足,教然后知困,然后能自强也。
2006-11-15 01:36
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复
redtek
金牌会员





积分 2902
发帖 1147
注册 2006-9-21
状态 离线
『第 13 楼』:  

在一个风雪交加的早上,再一次欣赏这精彩的贴子~:)



    Redtek,一个永远在网上流浪的人……

_.,-*~'`^`'~*-,.__.,-*~'`^`'~*-,._,_.,-*~'`^`'~*-,._,_.,-*~'`^`'~*-,._
2006-12-31 23:34
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复
weapfe
初级用户




积分 144
发帖 66
注册 2006-11-30
状态 离线
『第 14 楼』:  

混身酸痛全身无力的时候还想着看看这个帖子~~~~:)

2007-1-1 07:14
查看资料  发送邮件  发短消息 网志  OICQ (261372684)  编辑帖子  回复  引用回复
yunsenjhl
新手上路





积分 18
发帖 8
注册 2007-6-24
状态 离线
『第 15 楼』:  

慢慢看,逐步学习中。

2007-7-10 22:13
查看资料  发短消息 网志   编辑帖子  回复  引用回复

请注意:您目前尚未注册或登录,请您注册登录以使用论坛的各项功能,例如发表和回复帖子等。


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



论坛跳转: