需求:
每天下班时,将本地硬盘上的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. Android 使用JSON格式与服务器交互 中文乱码问题解决

    当前是在开发Android 程序时,客户端与服务器端采用JSON传送数据,发现中文乱码问题.不过这个问题的解决办法应该对所有java语言开发的项目都使用. 解决方法是: 1.客户端发送数据之间加上: ...

  2. Java基础学习总结(50)——Java事务处理总结

    一.什么是Java事务 通常的观念认为,事务仅与数据库相关. 事务必须服从ISO/IEC所制定的ACID原则.ACID是原子性(atomicity).一致性(consistency).隔离性(isol ...

  3. 洛谷—— P1017 进制转换

    https://www.luogu.org/problem/show?pid=1017#sub 题目描述 我们可以用这样的方式来表示一个十进制数: 将每个阿拉伯数字乘以一个以该数字所处位置的(值减1) ...

  4. spring接收对象数组实例

    JS var param= new Array(); var one= new Object; one.id = '1'; one.name= 'simba1'; param.push(one); v ...

  5. 通过 Microsoft iSCSI Software Target 提供存储服务

    软件下载地址: Microsoft iSCSI Software Target 3.3 下载完后成解压软件包如下: 安装官方的描述Target 端也就是服务端 只支持Windows Server 20 ...

  6. 解题报告 之 HDU5305 Friends

    解题报告 之 HDU5305 Friends Description There are  people and  pairs of friends. For every pair of friend ...

  7. c#.net公共帮助类

    c#.net公共帮助类 比较全面的c#帮助类 比较全面的c#帮助类,日常工作收集,包括前面几家公司用到的,各式各样的几乎都能找到,所有功能性代码都是独立的类,类与类之间没有联系,可以单独引用至项目,分 ...

  8. Auto Layout深入理解,及masonry简单介绍

    本篇博客是本人在学习自己主动布局过程中对自己主动布局的理解和整理,分三部分介绍,内容可能会有所反复.见谅. 一.autosizing与Auto Layout对照,及Auto Layout简单介绍 1. ...

  9. fastjson排序 Map多层嵌套转换自动排序问题终极解决方案

    阅读更多 最近项目中用到了fastjson(1.2.15)需要将前端多层嵌套json转换为map,由于map的无序性,想了很多办法,最终找到使用 Map m= JSONArray.parseObjec ...

  10. java的对象锁和对象传递

    1.对象传递 在JAVA的參数传递中,有两种类型,第一种是基本类型传递,比如int,float,double等,这样的是值传递,第二种是对象传递,比方String或者自己定义的类,这样的是引用传递. ...