需求:
每天下班时,将本地硬盘上的projects目录压缩为rar文件,文件名中必须含有当天日期信息,例如projects_20070902.rar.

分析:
1. 压缩可以调用WinRAR的命令行版本rar.exe来完成;
2. 难点是如何生成含有当天日期的文件名,date可以输出当天日期,但如何转换为20070902这种格式需要一定技巧。

实战一:万事开头易
首先要解决的是怎么调用rar.exe来压缩文件。rar.exe在WinRAR安装目录下,复制一个过来即可。使用前可以先用rar /?看看help, 但千万别被这么多参数吓坏,我们只要学会最简单的就行。网上搜搜例子,自己再试验试验,不难写出下面的压缩命令:

代码:
rar a "projects.rar" @backup.lst

backup.lst中是需要备份的目录/文件列表:

backup.lst:

代码:
d:\Work\Projects

如果某个目录下的某些文件不需要备份<!--more-->,可以通过exclude.lst文件来排除:

exclude.lst:

代码:
d:\Work\Projects\Private

压缩命令调整为:

代码:
rar a -x@exclude.lst "projects.rar" @backup.lst

至此,我们已经知道如何调用rar.exe来压缩文件,同时掌握了backup.lst和exclude.lst文件的使用,想要备份什么以及不想备份什么,一切已经尽在掌握中^o^

实战二:我for故我强
接着要解决是需求中的难点:如何生成含有当天日期的文件名。这个问题在稍微高级一点的语言中都不是问题,但在纯CMD命令行下,还真没有方便便捷的法门,我们得来点曲线救国,先date一下:

引用:
lifesinger@bpwang ~# date /T
2007/09/02 日

通过date命令可以输出日期字符串,但怎样才能将这个字符串赋值给一个变量呢?回想我们实战系列一里学会的九阴真经,或许我们可以先用date /T > date.txt将日期输出到文件,再用for来读取:

代码:
@echo off
date /T > date.txt
for /f %%i in (date.txt) do set str=%%i
echo %str%

执行后,字符串已经保存到str变量中。 for真真不愧为九阴真经,那一挥刀之间的潇洒,获取永世的强大……
上面的脚本执行后将输出 2007/09/02,与我们的目标格式 20070902 只一步之遥了。进一步处理对for来说简直牛刀小试也:

代码:
date /T > date.txt
for /f %%i in (date.txt) do set str=%%i
for /f "delims=/ tokens=1,2,3" %%i in ("%str%") do set date_str=%%i%%j%%k

到了黄山脚下,没有不登顶的道理。结合实战一中的rar命令,来个一鼓作气:

代码:
@echo off

rem get date string
date /T > date.txt
for /f %%i in (date.txt) do set str=%%i
for /f "delims=/ tokens=1,2,3" %%i in ("%str%") do set date_str=%%i%%j%%k rem rar to file
set file_name=projects_%date_str%.rar
rar a -x@exclude.lst "%file_name%" @backup.lst rem del temp files
del /q /f date.txt

哇,运行上面的脚本,那雪白的字符,像天上的浮云一样漂亮的从窗口飘过。我for故我强,我强故我笑,叹老毛已老,试问天下英雄,谁敢与for争锋?

实战三:天外有天

古人思美女,有个绝佳的描述:“求之不得,寤寐思服,悠哉悠哉,辗转反侧”。上面仗着强大的for经,我们山路十八弯般的看似潇洒其实痛苦的把问题解决了。但那真实的直觉却告诉我:一定存在更简单优雅的方法。辗转反侧之余,且先打个游戏轻松轻松。游戏里mm的画风真不错,小桥流水清风拂面,山泉叮咚灵感飘飘……

游戏归游戏,现实的google江湖中,也有不少赏心悦目之境:

代码:
lifesinger@bpwang ~# echo %date%
2007/09/02 日

原来%date%就可以获取到当前日期,我们前面居然搞出一个date.txt文件读来读去,实在要羞愧死了……
继续观光游览:

代码:
lifesinger@bpwang ~# echo %date:~0,4%
2007
lifesinger@bpwang ~# echo %date:~5,2%
09
lifesinger@bpwang ~# echo %date:~8,2%
02
lifesinger@bpwang ~# echo %date:~0,4%%date:~5,2%%date:~8,2%
20070902

哇,一直以为九阴真经无敌天下,却不料江湖中还有如此强大的功夫。先不论孰强孰弱,我们先来看看这本九阳真经:

引用:
lifesinger@bpwang ~# set /?
Displays, sets, or removes cmd.exe environment variables.

SET [variable=[string]]

variable Specifies the environment-variable name.
string Specifies a series of characters to assign to the variable.

Type SET without parameters to display the current environment variables.

If Command Extensions are enabled SET changes as follows:

SET command invoked with just a variable name, no equal sign or value
will display the value of all variables whose prefix matches the name
given to the SET command. For example:

SET P

would display all variables that begin with the letter 'P'

SET command will set the ERRORLEVEL to 1 if the variable name is not
found in the current environment.

SET command will not allow an equal sign to be part of the name of
a variable.

Two new switches have been added to the SET command:

SET /A expression
SET /P variable=[promptString]

The /A switch specifies that the string to the right of the equal sign
is a numerical expression that is evaluated. The expression evaluator
is pretty simple and supports the following operations, in decreasing
order of precedence:

() - grouping
! ~ - - unary operators
* / % - arithmetic operators
+ - - arithmetic operators
<< >> - logical shift
& - bitwise and
^ - bitwise exclusive or
| - bitwise or
= *= /= %= += -= - assignment
&= ^= |= <<= >>=
, - expression separator

If you use any of the logical or modulus operators, you will need to
enclose the expression string in quotes. Any non-numeric strings in the
expression are treated as environment variable names whose values are
converted to numbers before using them. If an environment variable name
is specified but is not defined in the current environment, then a value
of zero is used. This allows you to do arithmetic with environment
variable values without having to type all those % signs to get their
values. If SET /A is executed from the command line outside of a
command script, then it displays the final value of the expression. The
assignment operator requires an environment variable name to the left of
the assignment operator. Numeric values are decimal numbers, unless
prefixed by 0x for hexadecimal numbers, and 0 for octal numbers.
So 0x12 is the same as 18 is the same as 022. Please note that the octal
notation can be confusing: 08 and 09 are not valid numbers because 8 and
9 are not valid octal digits.

The /P switch allows you to set the value of a variable to a line of input
entered by the user. Displays the specified promptString before reading
the line of input. The promptString can be empty.

Environment variable substitution has been enhanced as follows:

%PATH:str1=str2%

would expand the PATH environment variable, substituting each occurrence
of "str1" in the expanded result with "str2". "str2" can be the empty
string to effectively delete all occurrences of "str1" from the expanded
output. "str1" can begin with an asterisk, in which case it will match
everything from the beginning of the expanded output to the first
occurrence of the remaining portion of str1.

May also specify substrings for an expansion.

%PATH:~10,5%

would expand the PATH environment variable, and then use only the 5
characters that begin at the 11th (offset 10) character of the expanded
result. If the length is not specified, then it defaults to the
remainder of the variable value. If either number (offset or length) is
negative, then the number used is the length of the environment variable
value added to the offset or length specified.

%PATH:~-10%

would extract the last 10 characters of the PATH variable.

%PATH:~0,-2%

would extract all but the last 2 characters of the PATH variable.

Finally, support for delayed environment variable expansion has been
added. This support is always disabled by default, but may be
enabled/disabled via the /V command line switch to CMD.EXE. See CMD /?

Delayed environment variable expansion is useful for getting around
the limitations of the current expansion which happens when a line
of text is read, not when it is executed. The following example
demonstrates the problem with immediate variable expansion:

set VAR=before
if "%VAR%" == "before" (
set VAR=after
if "%VAR%" == "after" @echo If you see this, it worked
)

would never display the message, since the %VAR% in BOTH IF statements
is substituted when the first IF statement is read, since it logically
includes the body of the IF, which is a compound statement. So the
IF inside the compound statement is really comparing "before" with
"after" which will never be equal. Similarly, the following example
will not work as expected:

set LIST=
for %i in (*) do set LIST=%LIST% %i
echo %LIST%

in that it will NOT build up a list of files in the current directory,
but instead will just set the LIST variable to the last file found.
Again, this is because the %LIST% is expanded just once when the
FOR statement is read, and at that time the LIST variable is empty.
So the actual FOR loop we are executing is:

for %i in (*) do set LIST= %i

which just keeps setting LIST to the last file found.

Delayed environment variable expansion allows you to use a different
character (the exclamation mark) to expand environment variables at
execution time. If delayed variable expansion is enabled, the above
examples could be written as follows to work as intended:

set VAR=before
if "%VAR%" == "before" (
set VAR=after
if "!VAR!" == "after" @echo If you see this, it worked
)

set LIST=
for %i in (*) do set LIST=!LIST! %i
echo %LIST%

If Command Extensions are enabled, then there are several dynamic
environment variables that can be expanded but which don't show up in
the list of variables displayed by SET. These variable values are
computed dynamically each time the value of the variable is expanded.
If the user explicitly defines a variable with one of these names, then
that definition will override the dynamic one described below:

%CD% - expands to the current directory string.

%DATE% - expands to current date using same format as DATE command.

%TIME% - expands to current time using same format as TIME command.

%RANDOM% - expands to a random decimal number between 0 and 32767.

%ERRORLEVEL% - expands to the current ERRORLEVEL value

%CMDEXTVERSION% - expands to the current Command Processor Extensions
version number.

%CMDCMDLINE% - expands to the original command line that invoked the
Command Processor.

简言之,set命令的作用是显示、设置或删除cmd.exe的环境变量。简单对比的话,可以将set理解成vbs里的dim, 或是js里的var. set的一般性用法在上面的经书中已经讲得很详细了。在这里我想引用中国DOS联盟论坛Will Sort的一篇文章来介绍set命令中最难理解的延迟扩展:

引用:
在中国DOS联盟论坛找到一篇Will Sort的解释文章,言简意赅的解释了环境变量延迟扩展,摘录于此,以备查看:

关于环境变量延迟扩展,使用set /?可以查看到部分说明,不过考虑到其粗劣的翻译水平,建议在查看之前,首先chcp 437切换为英文查看原英文说明。鉴于文中已说得十分详尽,而且有数个代码示例,应该不难理解。在此仅略作一些补充。

在许多可见的官方文档中,均将使用一对百分号闭合环境变量以完成对其值的替换行为称之为“扩展(expansion)”,这其实是一个第一方的概念,是从命令解释器的角度进行称谓的,而从我们使用者的角度来看,则可以将它看作是引用(Reference)、调用(Call)或者获取(Get)。

而命令解释器是扩展环境变量的行为大致如下:首先读取命令行的一条完整语句,在进行一些先期的预处理之后,命令被解释执行之前,会对其中用百分号闭合的字符串进行匹配,如果在环境空间中找到了与字符串相匹配的环境变量,则用其值替换掉原字符串及百分号本身,如果未得到匹配,则用一个空串替换,这个过程就是环境变量的“扩展”,它仍然属于命令行的预处理范畴。

而一条“完整的语句”,在NT的命令解释器CMD中被解释为“for if else”等含有语句块的语句和用“& | && ||”等连接起来的复合语句。

因此,当CMD读取for语句时,其后用一对圆扩号闭合的所有语句将一同读取,并完成必要的预处理工作,这其中就包括环境变量的扩展,所以在for中的所有语句执行之前,所有的环境变量都已经被替换为for之前所设定的值,从而成为一个字符串常量,而不再是变量。无论在for中将那些环境变量如何修改,真正受到影响的只是环境变量空间,而非for语句内部。

而为了能够在for语句内部感知环境变量的动态变化,CMD设计了延迟的环境变量扩展特性,也就是说,当CMD读取了一条完整的语句之后,它不会立即执行变量的扩展行为,而会在某个单条语句执行之前再进行扩展,也就是说,这个扩展行为被“延迟”了。

延迟环境变量扩展特性在CMD中缺省是关闭的,开启它的方法目前有两个:一是CMD /vn,它会打开一个新的命令行外壳,在使用exit退出这个外壳之前,扩展特性始终有效,常用于命令行环境中;二是setlocal EnableDelayedExpansion,它会使环境变量的修改限制到局部空间中,在endlocal之后,扩展特性和之前对环境变量的修改将一同消失,常用于批处理语句中。

上面的引用可能有点抽象,我举一个例子来说明延迟环境变量扩展特性:

testSet.cmd:

代码:
@echo off

rem 打开延迟扩展特性
setlocal enabledelayedexpansion set /a n=0
for /f %%i in ('dir /b') do (
set /a n=!n!+1
) echo 当前目录下的文件和目录总数为:%n% endlocal pause

上面的脚本能用来统计目录下的文件和目录总数,如果不打开延迟扩展,在for循环中将无法递增n.

好了,罗马不是一日建成的,如果上面的概念暂时没看懂,可以先记着有这样一本经书来查阅就可以了。我们言归正题,看看用set如何来解决我们最初的问题:

backup.cmd:

代码:
@echo off

rem get date string
set date_str=%date:~0,4%%date:~5,2%%date:~8,2% rem rar to file
set file_name=projects_%date_str%.rar
rar a -x@exclude.lst "%file_name%" @backup.lst

原来费劲周折好不容易通过for才获取到的日期字符串,现在用set一句话就搞定了^o^
上面的代码看起来漂亮多了,嘿嘿

小结:寻找最恰当的武器

在程序员的世界里,经常面临着各种争议和多种选择,像C++和C#的兄弟打架,C#和Java长久宿怨,还有php、asp、jsp等各种脚本语言之间的争风吃醋,这些争吵喧闹一定程度上促进了大众对这些语言的了解以及这些语言自身的发展。但如果因为精通某种语言或技术,就一味的只用这一种语言或技能来解决所有问题,在很多时候这是不明智的。在实战系列一中我极力推销和强调for的强大功能,for虽强大,但有它的适用范围,一味滥用就会导致此系列实战二中的费力不讨好。在这里,set明显比for好用^o^

对各种语言技能,对各种工具,我们应该尽量先有个初略的大体了解,然后解决具体问题时,再挑选最合适的工具来做,这往往能事半功倍。
且记于此,与各位朋友共勉。

http://blog.csdn.net/xhhjin/article/details/7311893

跟我学CMD实战系列之二 ——数据压缩备份的更多相关文章

  1. AspNetCore-MVC实战系列(二)之通过绑定邮箱找回密码

    AspNetCore - MVC实战系列目录 . 爱留图网站诞生 . AspNetCore - MVC实战系列(一)之Sqlserver表映射实体模型 . AspNetCore-MVC实战系列(二)之 ...

  2. 基于 abp vNext 和 .NET Core 开发博客项目 - Blazor 实战系列(二)

    系列文章 基于 abp vNext 和 .NET Core 开发博客项目 - 使用 abp cli 搭建项目 基于 abp vNext 和 .NET Core 开发博客项目 - 给项目瘦身,让它跑起来 ...

  3. MP实战系列(十二)之封装方法详解(续二)

    继续MP实战系列(十一)之封装方法详解(续一)这篇文章之后. 此次要讲的是关于查询. 查询是用的比较多的,查询很重要,好的查询,加上索引如鱼得水,不好的查询加再多索引也是无济于事. 1.selectB ...

  4. SpringBoot基础实战系列(二)springboot解析json与HttpMessageConverter

    SpringBoot解析Json格式数据 @ResponseBody 注:该注解表示前端请求后端controller,后端响应请求返回 json 格式数据前端,实质就是将java对象序列化 1.创建C ...

  5. [.NET领域驱动设计实战系列]专题二:结合领域驱动设计的面向服务架构来搭建网上书店

    一.前言 在前面专题一中,我已经介绍了我写这系列文章的初衷了.由于dax.net中的DDD框架和Byteart Retail案例并没有对其形成过程做一步步分析,而是把整个DDD的实现案例展现给我们,这 ...

  6. vue全家桶(Vue+Vue-router+Vuex+axios)(Vue+webpack项目实战系列之二)

    Vue有多优秀搭配全家桶做项目有多好之类的咱就不谈了,直奔主题. 一.Vue 系列一已经用vue-cli搭建了Vue项目,此处就不赘述了. 二.Vue-router Vue的路由,先献上文档(http ...

  7. Python3实战系列之二(获取印度售后数据项目)

    问题:续接上一篇.说干咱就干呀,勤勤恳恳写程序呀! 目标:安装python和pycharm.要编写并运行python程序就需要电脑有开发工具和运行环境,所以此篇就是安装编辑和运行python程序的软件 ...

  8. Swing应用开发实战系列之二:设计日期选择面板窗口

    Swing本身没有提供什么华丽丽的日期时间选择控件,所以笔者就在网上搜了个第三方的jar包jdatepicker-1.3.2.jar,基于此设计了个很轻量的日期选择面板,很简单的.效果图如下所示: 代 ...

  9. Vue 项目实战系列 (二)

    上一章节我们已经把项目的初始化工作完成了,接下来我们再来进行具体的代码编写.这一节我们将完成如下的页面. 我们在src/目录下新建一个views文件夹,存放我们的主要页面文件.目录结构如下: cine ...

随机推荐

  1. amazeui学习笔记--css(常用组件6)--图标Icon

    amazeui学习笔记--css(常用组件6)--图标Icon 一.总结 1.关注用法即可:在 HTML 上添加添加 am-icon-{图标名称} class. <span class=&quo ...

  2. Codeforces Round #100 E. New Year Garland (第二类斯特林数+dp)

    题目链接: http://codeforces.com/problemset/problem/140/E 题意: 圣诞树上挂彩球,要求从上到下挂\(n\)层彩球.已知有\(m\)种颜色的球,球的数量不 ...

  3. jemter--录制的脚本设置循环次数不起作用

    以下是比较jmeter线程组中设置循环次数和循环控制器中设置循环次数的区别 1.jmeter生成的脚本没有step1(循环控制器)控制器,故循环在线程组中设置   2.badboy录制的脚本有setp ...

  4. GTK入门学习:glade的使用

    搭建好环境后,在终端敲 glade 就可以启动glade工具. glade的总体框图: 经常使用控件选择区:列举了经常使用的控件,经常使用的有三类:顶层(主窗体等).容器(各种布局容器等).控制和显示 ...

  5. ASCII码的问题

    数字0在ASCII的不同进制下表示:

  6. HDU 1406 完数 因子的和

    http://acm.hdu.edu.cn/showproblem.php?pid=1406 完数的定义:如果一个大于1的正整数的所有因子之和等于它的本身,则称这个数是完数,比如6,28都是完数:6= ...

  7. HDU 1045 Fire Net(行列匹配变形+缩点建图)

    题意:n*n的棋盘上放置房子.同一方同一列不能有两个,除非他们之间被墙隔开,这种话. 把原始图分别按行和列缩点 建图:横竖分区.先看每一列.同一列相连的空地同一时候看成一个点,显然这种区域不可以同一时 ...

  8. 想要搞BGM,没有歌曲链接怎么办?

    有对于想要做个个人网站BGM,而非商业用途和非法用途,这只是个小技巧,仅限于个人娱乐使用. 方法一: 首先打开酷狗网页端 搜索想要的音乐名字 进入播放页面 进入开发者模式(右键鼠标->检查或者直 ...

  9. nginx源代码分析--ngx_http_optimize_servers()函数

    这个函数做了连部分工作:1)以port为入口点 将实用的信息存放到hash表内 2)调用ngx_http_init_listening()函数 对port进行监听 1. 在ngx_http_core_ ...

  10. html5 Canvas和SVG的区别是什么(总结)

    html5 Canvas和SVG的区别是什么(总结) 一.总结 一句话总结:都是2D做图,svg是矢量图,canvas是位图.Canvas 是逐像素进行渲染的,适合游戏. 1.svg的全称是什么? S ...