zoukankan      html  css  js  c++  java
  • bat programming is easy and powerful

     用linux的角度来思考windows,习惯了linux的shell后,

    再来看windows的bat编程,就简单多了,简直就是理所当然

    实际上windows的cmd命令行和linux的shell命令行感觉基本上差不多了
    比如都有重定向 > , >>, 和管道 | 
    ipconfig /a >> ip.txt
    dir c: |more
    tree c: | find "call" (tree显示的结果像图行,其实是字符串)

    要习惯于看windows cmd的命令帮助,command /? ,里面的解释已经很详细很直白了

    这就像linux下的man “command”

    -----------------------

    当你熟练掌握了linux中的sed, awk, cut,grep等这些行编辑命令后,
    自然就能灵活地、得心应手地使用cmd中for if 等等命令的使用
    for [/options] %var in (set) do command [command-parameters]

    FOR /F "eol=; tokens=2,3* delims=, " %i in (...)...

    cmd支持命令简写:
    rd=rmdir,md=mkdir,ren=rename,
    type:显示文本文件到标准输出,print是真的用打印机打印输出
    prompt:修改命令提示符,对应linux bash中是设置环境变量ps的值

      用prompt命令,可以将cmd设置成类似bash的样子:>prompt [$d $t $p] # 

    move:移动文件,linux是mv命令
    xcopy:复制文件和目录树
    find:在文件内按行搜索字符串,linux中类似的命令是grep

    -------------------------------------
    cmd把命令后面的[options]叫开关switches,bash叫选项options
    cmd的开关通常不能合并在一起书写,而bash的选项可以合在一起
    find /V /N "somestring" filename
    netstat -tunl |grep "telnet"

    windows的系统命令一般放在%SystemRoot%Windowssystem32下,因此它就相当于
    linux的/sbin, /bin, /usr/bin, /usr/sbin

    命令shell中,每个命令执行完毕后,都会返回一个返回码,成功为0,失败为1.

    echo %errorlevel%: linux中用$! 表示

    ------------------------------

    变量延迟:

    在由&,&&,||,()组成的符合句中,变量的值取该语句之前的值,在该符合句中可以给变量赋值,

    但变量的新值,要在该语句的下一句才会生效,即:变量的值会“延迟“起作用

    利用变量延迟,可以交换两个变量的值而不用中间变量;

    要避免“变量延迟”的问题,使变量的新值在该复合句中即时生效,应该:

      setlocal enabledelayedexpansion

      .....  echo !delayed_var!

    变量延迟的机制:

      因为bat执行命令的机制是:首先将一条命令读入内存,在执行该命令之前,先做一些预处理工作,包括:替换循环变量

    如:  

    test]# for %i in (f1 f2) do ren %i %i.mp3  //执行时会首先将%i分别替换成f1, f2,然后才执行

    test]# ren f1 f1.mp3

    test]# ren f2 f2.mp3

      给该语句中的 “变量 %var%”赋值,这时候,因为这条语句还没有执行,所以当然是用该语句之前的值给

      变量赋值, 然后才执行这条语句。

    为了让语句中的变量,能够及时感知环境的变化,使用“变量延迟”技术, 让语句在执行之前,再次对其中的变量赋值,...

     事实上,在bat编程中,变量延迟也用得相当“普遍”,很平常的:凡是在for循环语句的结构体中,要改变“非迭代变量”的变量 的值,如

    累加,字符串连续串接等,都要使用变量延迟

    setlocal ...  注意和endlocal配合使用

    bat中可以使用通配符?,*

    ?: 表示0个或1个字符,*表示0个或任意个,注意?可以是没有,可以是0,并不一定要有一个字符

    如: dir /b ????? : 将匹配1到5个字符的所有文件(夹)

    -------------------- 

    在web,c,c++编程中,对于比较大的项目,往往会通过代码分割,写成多个文件

    同样的,如果要用bat实现比较复杂的任务(以后习惯用bat脚本来实现处理 windows下的任务)时,

    就要编写多个脚本.bat文件,这时相互之间的调用就要使用call命令...(但要注意call语句不同于函数调用,因为

    它不会阻塞原程序的执行)

    bat编程中,没有while...do的结构,要使用循环,是用 if...goto “lable"来实现的

    同样,也没有switch...case的结构,也是用 if...goto “lable"来实现的

     -----------------------------

    if语句的逻辑与和逻辑或?

    在bat编程中,不能用&& ||来表示逻辑与/或(有&&, ||,但它们是用来连接语句的), 要表示多个条件的 “逻辑与” 应该使用if语句的嵌套:

    if "%str1" == "%str2" (

      if "%str3"== "%str4%" (

        rem do something....

    )

    )

    choice命令?

    有的windows中没有choice命令,因为choice不是内部命令,它是一个外部命令,choice.exe/choice.com

    但是也没有必要,一定用choice命令,因为用set /p, if, goto 命令完全可以代替choice命令...

    字符串的连接?

    bat脚本中字符串连接直接挨着写就好了,不用什么+.

     -------------------------------------

    bat编程中的pushd和popd的有什么作用?

    当需要在多个目录中反复切换时,使用pushd和popd是最好的方法,比cd命令更方便更直观

    linux中的pushd和popd,dirs命令:

    pushd parameter_dir  ====  “current_dir" pushd + cd  parameter_dir

    cd -   其中的- :  = $OLDPWD

    pushd; pushd +2; popd;  popd +1; 栈总是从上到下, 从0, 1,2 开始的,所以切换时总是整数+加号

    dirs -c: 清除栈中所有的目录

    popd命令总是不能清除当前正在使用的目录!

    windows:  pushd %~dp0 ;  pushd “%~dp0test" ... popd:  即: 切换到某个目录,执行完某些操作后,再返回到原来的目录

     --------------------------------------------

     --------------------------------------------

    for循环:

    : for变量的扩展是“全局”的,即:跟使不使用/d, /r , /f等完全无关

    :for的4种形式:包括:不使用扩展的纯的裸的、使用/d的、使用/l的、使用/f的,

    每种格式都是有严格规定的,只能使用每种情况下规定的格式和许可的内容: 如:

    for %%i in (*.mp3)/(*) do echo %%i  : 这个是可以的,可以使用通篇符,而且主要是使用通配符

    for /f  %%i in (*.mp3)/(*) do echo %%i  : 这个就是不可以的,因为在for /f 的三种格式里都没有使用通配符

    默认的for循环(不带任何扩展参数的时候) 只处理file-set,(将把set当作一个或一组文件,是文件)不处理目录

    file-set的表示方法只有两种?!: 一种是使用通配符*,?, 另一种是直接输入文件名列表集合,用空格分割

    file-set中并不能执行命令,不像linux中使用后引号表示命令执行结果,

    (for命令的set集合中,要想使用 “子命令“的执行结果,需要使用 /f 扩展参数!!)

    所以,即使你单或 双引号,for也只是认为那是几个文件的集合:

    如: for %%i  in ( 'dir /b mp3') do (ren %%i %%i.mp3)      将会认为dir, /b, mp3是三个文件,

      将它们重命名,自然执行 ren /b /b.mp3就会出错了

    for /d: 对这个参数,以前一直有个误解,认为只匹配文件夹,对文件不起作用。实际上,这种想法是错误的:

          1.  有这个/d与没有/d,对文件的解析完全是没有影响到,文件该解析该匹配的,照样匹配,照样执行命令就好象没有这个/d一样

          2. 只有当后面括号中使用通配符*, *.*, (????.????足够多?)的时候,才匹配目录,而不匹配文件,也就是说,只有/d跟* 在一起的时候,才起作用

    for /r :  参数/r, 搜索指定路径及所有子目录中与set相符合的所有文件,注意是指定路径及所有子目录。

      1、set中的文件名如果含有通配符(?或*),则列举/R参数指定的目录及其下面的所用子目录中与set相符合的所有文件,无相符文件的目录则不列举。
      2、如果set中为具体文件名,不含通配符,则枚举该目录树(即列举该目录及其下面的所有子目录)(并在后面加上具体的文件名),而不管set中的指定文件是否存在。
      例:for /r c: %%i in (*.exe) do echo %%i --把C盘根目录,和每个目录的子目录下面全部的EXE文件都列出来了

        for /r c: %%i in (boot.ini) do echo %%i --枚举了c盘所有目录
        for /r d:ackup %%i in (1) do echo %%i --枚举dackup目录
        for /r c: %%i in (boot.ini) do if exist %%i echo %%i --很好的搜索命令,列举boot.ini存在的目录

     for /f:

    前面的for都只是处理文件和目录,把它们作为一个整体进行处理,不涉及文件里面的内容,

    但如果要对文件里面的内容进行处理的话,就要用/f 扩展,但并不表示for /f不能用来处理文件

     而且只有这个时候,才能使用单引号,双引号,后引号等,才能使用 执行命令结果

     for /f: 以前有一种误解:因为for /f要将file-set中的每个文件的内容要读入内存进行处理,所以就以为

      for /f就不能用来处理文件,只能用来处理文件的内容。其实for  /f同样可以用来处理文件,如:

      文件名的输出,文件的重命名,文件的复制删除等等,只不过这时我不需要、我可以忽略:文件内容的分割处理等结果

      我不处理那些%%j, %%k, 等等的“隐藏变量”, 我只处理%%i 这个基本的文件循环变量本身就可以了(这时的%%i

      代替的是文件本身,跟使用tokens的%i代表的是不同的!) 当然,当我需要对文件里面的内容进行解析、分割,

      并输出解析结果时,我可以要tokens, delims等等... 而且for /f格式也说得很清楚: for /f [“options”] %var in (3种格式)    do ... 那些分割解析的只是:[options]!

    for  %i in (set) do格式只能使用通配符或一个一个的列举方式的fileset,

    如果这两种方式都不适合,要用dir命令来列举的时候,就要使用: for /f %i in ('dir /b /a-d /s') do echo %i....

    :最神奇的是,当tokens和%%cycle_var连用的时候, 在for /f "tokens=1,2,3,4" %i in ("this is a test") do echo %i %J %k %L中,隐含变量(%i后面的变量)是要分顺序的!只能是j,k,l...不能是其他字母或大写的字母,否则就无效!

    如:上面的语句,只输出: this %J a %L    而且这里的%i代表的不再是文件名本身,而是分割后的tokens...

    ---------------------------------------

     :dir 要只显示文件,就要把属性directroy过滤掉: dir /a-d, 要修改文件的属性,需要使用attrib命令...

    :有时候,用*或者?也可以代替for循环?如对文件夹下的所有文件进行重新命名: 可以不使用for循环,直接用:

    rename * *.mp3   // 增加扩展名

    rename *.* *.mp3  // 全部扩展名更改为mp3

    rename ????.txt ????.mp3

    rename ?????????????????????????.txt  ?????????????????????????.mp3( ?问号越多, 可以命名的文件越多?)

    这里要注意的是: 问号?是不能代替扩展名的.xxx, 在上面的命令中,使用rename ???? ????.mp3将是错误的???

    : 通配符虽然可以代表任意字符, 但是 在一次循环中,前后代表的字符/文件/含义在当前这次循环/操作中,

      “通常”是一致的,"后面的可以替代前面的,但前面的*不一定就能代替后面的内容“,如:

        ren *.mp3  *   // 这个命令本意是要去掉文件的扩展名,但这样实际上文件是没有改变和影响到

    :关于rename的“古怪"规定: 新的文件名不能带路径,即使跟原来的路径相同也不行:

    (网上的说法:

    旧文件可以使用绝对路径,也可以使用相对路径,但是,新文件名不能使用任何路径,只能是新的文件名,即使这个路径就是当前目录。

    例如:需要修改 d: estabc.txt这个文件的名字为xyz.txt的话,如果当前路径位于d: est,那么,命令可以写成:ren abc.txt xyz.txt、ren d: estabc.txt xyz.txt,

    但是,绝对不能写成ren d: estabc.txt d: estabc.txt这样的格式。

    之所以会有这个古怪的规定,可能是一旦把路径写成另外的目录,ren就具备了“移动文件+重命名文件”的功能 了,这和它的定位不相符(内部的代码编写就跟move重复了)

    要遍历整个目录,dir命令的/S选项,以及for命令的/R选项都有遍历功能

    : 很重要的一点是: 要对bat中的语句进行排错,一是在命令行一句一句执行,二是开启echo on 可以看到

      (交互式的)每一句执行的结果,清楚地看到是哪条语句出错

     :注意两种变量的不同表示方法:循环变量用%%i表示,而普通变量用 %var%表示

    --------------------------------------

    bat举例:

    rem @echo off
    cls

    setlocal enabledelayedexpansion
    echo author: bkylee
    echo date: %date%,%time%
    echo functionality: batch to delete mp3 files extention
    echo scenario: the command "ren *.mp3 *" can not bring about the result above
    echo.

    pushd %~dp0%

    rem if not exist "mp3" (
    rem echo "error 1: no mp3 folder"
    rem goto end
    rem )


    echo --------------------------------------------------
    echo start to rename...

    set warnings = ""

    for %%i in (*) do (
    if "%%~xi" == ".mp3" (
    ren %%i %%~ni

    rem ----: 在下面的else前后都必须有一个空格,使else与括号) else ( 相隔离,否则就会出错!
    ) else (
    set warnings = !warnings!"%%i is not mp3 file"
    )
    )

    echo --------------------------------------------------
    dir /b

    rem recover the enviornment before
    echo.

    echo %warnings%
    echo.

    endlocal

    popd

    :end
    echo "press any key to exit ..." & pause >nul

    资料来源于网络,其中,参考这篇文章,写得比较好,比较细:http://biancheng.dnbcw.info/python/341315.html 

  • 相关阅读:
    delphi point数据类型
    Sql Server 2008 R2链接服务器Oracle数据库
    ORA-28000 账号被锁定的解决办法
    [Oracle] sqlplus / as sysdba ora-01031 insufficient privileges
    Oracle的操作系统认证(/ as sydba 登录方式)
    Delphi使用线程TThread查询数据库
    oracle
    统计字符串中字符出现的次数-Python
    Jmeter保存下载的文件
    如何在Microsoft Store上免费获得 HEIF、HEVC 编码支持
  • 原文地址:https://www.cnblogs.com/bkylee/p/4893390.html
Copyright © 2011-2022 走看看