Board logo

标题: [原创][XP]文件备份器V2.4(Final) [07-4-8更新] [打印本页]

作者: namejm     时间: 2006-5-22 23:35    标题: [原创][XP]文件备份器V2.4(Final) [07-4-8更新]

  当前讨论:

  本人机子为XP系统,要备份的文件为"c:\program files\家易理财 2004\date"文件夹下的文件,该文件夹下只有几个.mdf格式(该软件自带格式)的数据文件,保存到"E:\家易理财数据备份"文件夹下,备份的时间为每天的12:00 19:00 22:00。今天21点的时候打开电脑,提示说备份服务不正常,22点之前改动了date文件夹下的文件,22点之后查看"E:\家易理财数据备份"下的日志,发现没有备份记录,再查看该文件夹下的文件,没有任何改动,打开任务管理器查看进程,cmd.exe和xcopy.exe一直在运行,在C:\WINDOWS\Tasks下查看状态,At1空白(12:40的时候已经执行了备份动作),At2为"错过",At3为"正在运行",请问这是什么原因?

  这个问题已经解决,解决办法见6楼的描述。

  经过N次修改的备份程序完整代码如下。

  已知的问题:

      1、CMD复制某些文件时会出错,会导致文件不能完整地备份,原因正在查找中,不过几率相当低;

  2、暂无,期待大家更多的测试反馈

@echo off
::    文件备份器V2.4(for WinXP only)  Code by JM  Renew on 2007-4-8 QQ:13132002
::         Thanks to willsort、bagpipe、pengfei……
::    出处:http://www.cn-dos.net/forum/viewthread.php?tid=20747
::
::  功能:1、自由指定要备份的目录(或文件)、位置、备份时间和任务名称
::        2、能检测输入是否正确
::        3、能生成备份日志
::        4、能多次添加备份任务
::        5、能批量停止指定的备份任务
::        6、能自动删除由本程序产生且不再使用的批处理程序和注册表信息
::
::  原理:只有当源文件修改时间比目标文件的修改时间新时才更新文件

:: if not "%1"=="$" %comspec% /f:on /c %0 $ && goto :eof
:: 屏蔽掉上一句,用Tab\Shift+Tab可实现同样功能
mode con lines=26
title 文件备份器
color 1f
cls

rem   =========检测系统是否支持本程序=============
:check_system
ver|find "XP">nul || goto system_error

rem   =========检测当前用户是否具有管理员权限=============
:check_popedom
net users %username%|findstr /i "\*administrator ">nul || goto popedom_error

rem    =======输入要备份文件的路径并检测输入是否正确=======
:input_source
mode con lines=26
cls
color 1f
title 文件备份器-请输入源文件路径
echo                               ╭────────╮
echo           ╭─────────┤选择要备份的文件├─────────╮
echo           │                  ╰────────╯                  │
echo           │                                                        │
echo           │         本程序能把指定文件在指定时间内备份到指定位     │
echo           │                                                        │
echo           │    置。请把要备份的文件(或文件夹)拖曳至本窗口(推荐     │
echo           │                                                        │
echo           │    做法),或者手工输入需要备份文件的绝对路径或相对     │
echo           │                                                        │
echo           │    路径(请勿输入非法符号),然后回车确认。              │
echo           │                                                        │
echo           │        自动完成文件名请按Tab\Shift+Tab,可多次选择。   │
echo           │                                                        │
echo           │        为了不错误删除数据,使用本软件前请查看注意      │
echo           │                                                        │
echo           │    事项!切记切记! (查看备份脚本程序请按 V )          │
echo           │                                                        │
echo           ╰────────────────────────────╯
echo.
echo            查看注意事项请按 1                              退出请按 0
echo           ──────────────────────────────
echo                                查看已存在的备份任务请按 2                 
echo.
set source=:
:: 上面这句为后面去除引号做铺垫,冒号绝对不能省略;否则,当输入为空时按下回车会出错。
set /p source=           请输入要备份文件的路径:
set "source=%source:"=%"
:: 上面这句为判断%source%中是否存在引号,有则剔除。
if "%source%"==":" goto input_source
if "%source%"=="0" exit
if "%source%"=="1" goto notice
if "%source%"=="2" goto backup_tasks
if /i "%source%"=="v" goto view_batch
if not exist "%source%" goto source_noexist
for %%i in ("%source%") do if "%%~fi"=="%%~di\" goto forbid_to_backup
:: 判断要备份的是文件还是文件夹,为以后的xcopy操作设置标志
pushd "%source%" 2>nul && (popd & set folder=yes) || (set folder=)
goto input_destination


:backup_tasks
cls
color 1f
title 文件备份器-已存在的备份任务
echo.
at
echo -------------------------------------------------------------------------------
echo.
echo         ╔══════════════════════════════╗
echo         ║ 如果要停止某个备份任务,请输入该任务的ID号,然后按回车即可 ║
echo         ║                                                            ║
echo         ║       多个ID号之间用空格分隔,停止所有计划任务请按 A       ║
echo         ║                                                            ║
echo         ║     退出请按 0 ,返回上一步请按除0、A和ID数字之外的任意键  ║
echo         ╚══════════════════════════════╝
echo.
set ID=
set /p ID=           请输入不再需要的备份任务的ID:
if "%ID%"=="0" exit
if /i "%ID%"=="a" (
    at /del /yes
    call :del_unused
    goto backup_tasks
)
:: 以下语句的作用是:如果停止了某项备份任务,则检查硬盘上由本程序生成的cmd文件中,
:: 不在at任务列表中的有哪些;如果有,则删除该cmd,同时删除注册表中对应的字符串值;
:: 如果没有,则不作任何删除操作;
(for %%i in (%ID%) do at %%i /del /yes 2>nul) && (
    call :del_unused
    goto backup_tasks
) || goto input_source

rem    =======输入文件保存路径并检测输入是否正确=======
:input_destination
cls
color 1f
title 文件备份器-请输入目标文件路径
echo.
echo.
echo                               ╭────────╮
echo           ╭─────────┤  选择保存位置  ├─────────╮
echo           │                  ╰────────╯                  │
echo           │        操作说明:                                      │
echo           │                                                        │
echo           │            请输入保存位置的绝对路径或者相对路径        │
echo           │                                                        │
echo           │        (注意:必须在半角状态下输入冒号和反斜杠;       │
echo           │                                                        │
echo           │        请勿输入非法的路径名符号),或者把一个已         │
echo           │                                                        │
echo           │        存在的文件夹拖曳至本窗口,然后回车确认。        │
echo           │                                                        │
echo           │          ╭────────────────╮          │
echo           ╰─────┤  查看各磁盘分区剩余空间请按 9  ├─────╯
echo                       ╰────────────────╯
echo.
echo            返回上一步请按 1                                退出请按 0
echo           ──────────────────────────────
echo.
set destination=:
set /p destination=           请输入备份文件的保存路径:
set "destination=%destination:"=%"
:: 上面这句为判断%destination%中是否存在引号,有则剔除
if "%destination%"==":" goto input_destination
if "%destination%"=="0" exit
if "%destination%"=="1" goto input_source
if "%destination%"=="9" goto freesize
:: 取文件夹保存位置完整路径或者文件保存位置的目录名
for /d %%i in ("%source%.*") do set "destination=%destination%\%%~nxi"
for %%i in ("%destination%") do set "destination=%%~fi"
set "subarea=%destination:~0,1%"
for %%i in ("%destination%") do if "%%~fi"=="%%~di\" goto forbid_to_build_1
echo "%destination%" | findstr /i /c:"%source%">nul && goto forbid_to_build_2
if not exist %subarea%:\ goto subarea_noexist
:: 下面一句取日志名为要备份文件(夹)的文件名
for %%i in ("%source%") do set "name_log=%%~ni"
if exist "%destination%\%name_log%_log.log" goto whether_add
if exist "%destination%" goto whether_over

:over_write
rd /q /s "%destination%" 2>nul
md "%destination%" 2>nul
(echo.
echo                                 备份日志)>"%destination%\%name_log%_log.log"

:input_date
cls
color 1f
title 文件备份器-请输备份入日期
echo                               ╭────────╮
echo           ╭─────────┤ 请输入备份日期 ├─────────╮
echo           │                  ╰────────╯                  │
echo           │                                                        │
echo           │        1.若在每月的某几天备份,请输入从1到31的任意     │
echo           │                                                        │
echo           │    数字,比如1,3,4;若只在每月1号备份,请输入"1,";   │
echo           │                                                        │
echo           │        2.若在每周的某几天备份,请输入星期几的代码      │
echo           │                                                        │
echo           │    (M,T,W,Th,F,S,Su);如果指定日期较多,在查看任务     │
echo           │                                                        │
echo           │    列表的时候,日期一栏将用省略号显示;                │
echo           │                                                        │
echo           │        3.数字与字母不可混用;数字行或字母行首尾均无    │
echo           │                                                        │
echo           │    任何符号,其间用逗号分隔;请严格按照本格式填写!    │
echo           │                                                        │
echo           ╰────────────────────────────╯
echo.
echo            返回上一步请按 1                                退出请按 0
echo           ──────────────────────────────
echo                                   每天都备份请按 A
echo.
set copydate=
set /p copydate=          请输入备份日期:
if "%copydate%"=="" goto input_date
if "%copydate%"=="," goto input_date
if "%copydate%"=="0" exit
if "%copydate%"=="1" goto input_destination
if "%copydate%"=="1," goto input_time
if /i "%copydate%"=="a" goto all_date
:: 检查日期输入是否正确
set /a num="%copydate:~0,1%" 2>nul&&(
    goto check_numerical_date) || (
    goto check_alphabetical_date
)

:check_alphabetical_date
for %%i in (%copydate%) do (
    echo "M T W Th F S Su"|findstr /i "%%i">nul || goto date_error
)
goto input_time

:check_numerical_date
for %%i in (%copydate%) do (
    if %%i lss 1 goto date_error
    if %%i gtr 31 goto date_error
)

:input_time
cls
color 1f
title 文件备份器-请输入时间
echo.
echo                               ╭────────╮
echo           ╭─────────┤ 请输入备份时间 ├─────────╮
echo           │                  ╰────────╯                  │
echo           │        操作说明:                                      │
echo           │                                                        │
echo           │            请按格式输入备份时间,多个时间用空格        │
echo           │                                                        │
echo           │        分隔。该时间用24小时制(既从00:00到23:59)        │
echo           │                                                        │
echo           │        的小时:分钟格式表示。                           │
echo           │                                                        │
echo           │            例如:想分别在上午8点30分和下午4点进        │
echo           │                                                        │
echo           │        行备份,请在同一行输入8:30 16:00(注意:两       │
echo           │                                                        │
echo           │        个时间点之间有一个空格)                         │
echo           │                                                        │
echo           ╰────────────────────────────╯
echo.
echo            返回上一步请按 1                                退出请按 0
echo           ──────────────────────────────
echo.
set copytime=
set /p copytime=           请输入备份时间:
if "%copytime%"=="" goto input_time
if "%copytime%"=="0" exit
if "%copytime%"=="1" goto input_date
:: 检查时间输入是否正确
for %%i in (%copytime%) do (
    for /f "tokens=1* delims=:" %%j in (%%i) do (
        if %%j lss 0 goto time_error
        if %%j gtr 23 goto time_error
        if %%k lss 0 goto time_error
        if %%k gtr 59 goto time_error
    )
)

rem    =======输入备份任务名称=======
:input_name
cls
color 1f
title 文件备份器-备份任务名称
echo.
echo                               ╭────────╮
echo           ╭─────────┤  备份任务名称  ├─────────╮
echo           │                  ╰────────╯                  │
echo           │        操作说明:                                      │
echo           │                                                        │
echo           │            请输入备份任务的名称,然后回车确认。        │
echo           │                                                        │
echo           │        本程序将在"系统安装盘:\Program Files\备份       │
echo           │                                                        │
echo           │        任务程序"下生成"备份任务名称_backup.cmd"        │
echo           │                                                        │
echo           │        这一备份批处理脚本程序。如需更改此备份任务      │
echo           │                                                        │
echo           │        的部分功能,请用文本编辑工具对批处理文件        │
echo           │                                                        │
echo           │        进行编辑。                                      │
echo           │                                                        │
echo           ╰────────────────────────────╯
echo.
echo            返回上一步请按 1                                退出请按 0
echo           ──────────────────────────────
echo.&echo.
set name=
set /p name=           请输入备份任务的名称:
if "%name%"=="" goto input_name
if "%name%"=="0" exit
if "%name%"=="1" goto input_time
if exist "%ProgramFiles%\备份任务程序\%name%_backup.cmd" goto name_exist

call :list
echo         ╔══════════════════════════════╗
echo         ║  退出请按 0 ,返回上一步请按 1 ,放弃并开始新的备份请按 B  ║
echo         ║                                                            ║
echo         ║             继续下一步请按除0、1和B之外的任意键            ║
echo         ╚══════════════════════════════╝
echo.
set choice=
set /p choice=       请选择操作代码(0/1/B/其他键):
if "%choice%"=="0" exit
if "%choice%"=="1" goto input_name
if /i "%choice%"=="b" (
    attrib /s /d -s -h -r "%destination%\*.*" 2>nul
    rd /q /s "%destination%" 2>nul
    goto input_source
)
goto build_backup

:notice
cls
mode con lines=40
color 8e
title 文件备份器-注意事项
echo.
echo.
echo     ╔══════════════════════════════════╗
echo     ║                                                                    ║
echo     ║        1. 当程序提示某路径已存在时,强烈建议在作出覆盖操作前先查   ║
echo     ║                                                                    ║
echo     ║    看该目录下的内容,以免程序错误删除该目录下的所有内容,给您带    ║
echo     ║                                                                    ║
echo     ║    灾难性的损失。备份有风险,操作请谨慎!                          ║
echo     ║                                                                    ║
echo     ║        2. 路径名中,除了允许冒号和反斜杠符号紧跟盘符之外,其他位   ║
echo     ║                                                                    ║
echo     ║    置不能再含有半角状态下的以下11个符号,分别为:\、/、:、*、?、   ║
echo     ║                                                                    ║
echo     ║    "、<、>、(、)、|。输入其中任意一个符号,都会引起无法预料的错    ║
echo     ║                                                                    ║
echo     ║    误;在本程序中,文件名的命名也应遵守以上规定!                  ║
echo     ║                                                                    ║
echo     ║        3. 如果只输入"盘符+冒号"格式的路径,程序会把路径当作指定    ║
echo     ║                                                                    ║
echo     ║    盘的当前路径来处理,而不是指定盘的根目录。比如:假设系统安装    ║
echo     ║                                                                    ║
echo     ║    在C盘,在路径中只输入 C: ,则并不会认为是C盘根目录,而是C盘的   ║
echo     ║                                                                    ║
echo     ║    当前路径,默认为"C:\ducuments and settings\当前用户名";        ║
echo     ║                                                                    ║
echo     ║        4. 如果输入的路径不带盘符,则作为相对路径处理;             ║
echo     ║                                                                    ║
echo     ║        5. 本程序工作原理为:通过比较备份后文件与源文件的时间早晚   ║
echo     ║                                                                    ║
echo     ║    来决定是否进行复制操作,因此,任何改动备份后文件修改时间的操    ║
echo     ║                                                                    ║
echo     ║    作都会使程序不能及时更新源文件改动过的数据,请勿对备份后的文件  ║
echo     ║                                                                    ║
echo     ║    进行改名、添加或删除子文件等操作!                              ║
echo     ║                                                                    ║
echo     ╚══════════════════════════════════╝
echo.
echo                                                      按任意键返回上一步...
pause>nul
goto input_source

:whether_over
cls
color 0c
title 文件备份器-路径已存在
echo.
echo.
echo.
echo.
echo.
echo ________________________________________________________________________________
echo.
echo          您输入的路径"%destination%"已经存在,覆盖还是追加?
echo.
echo ________________________________________________________________________________
echo.
echo     ╔══════════════════════════════════╗
echo     ║   按O覆盖,按A追加,按V查看保存目录,按 1 返回上一步,按 0 退出    ║
echo     ╚══════════════════════════════════╝
echo.
echo.
set choice=
set /p choice=                           请选择(O/A/V/0/1):
if /i "%choice%"=="o" cls && goto over_write
if /i "%choice%"=="a" goto input_date
if /i "%choice%"=="v" call :view_directory && goto whether_over
if "%choice%"=="0" exit
if "%choice%"=="1" goto input_destination
goto whether_over

:whether_add
cls
color 0c
title 文件备份器-备份文件已存在
echo.&echo.&echo.&echo.&echo.
echo ________________________________________________________________________________
echo.
echo              "%destination%"
echo.
echo          下似乎已经存在以前的备份文件,覆盖此目录还是追加到此目录?
echo.
echo ________________________________________________________________________________
echo.
echo    ╔═══════════════════════════════════╗
echo    ║  按 V 查看保存目录,按 O 覆盖,按 A 追加,按 1 返回上一步,按 0 退出 ║
echo    ╚═══════════════════════════════════╝
echo.&echo.
set choice=
set /p choice=                           请选择(V/O/A/0/1):
if /i "%choice%"=="o" goto over_write
if /i "%choice%"=="a" cls && goto input_date
if /i "%choice%"=="v" call :view_directory && goto whether_add
if "%choice%"=="0" exit
if "%choice%"=="1" goto input_destination
goto whether_add

:freesize
::     假设字符串freesize长度范围为0~7(假设硬盘最大999G,换算成以M为单位则是7位数),
::  则首先在freesize前补足7个空格,然后直接取字符串的后7个字符,即可得到右对齐排列
::  的数字freesize。同理,假设字符串volume的长度范围为0~20(卷标名最长可达32位,但是
::  为了兼顾排版的显示,只取后20位)。
::  主体代码由willsort提供
cls
color 2e
title 文件备份器-各分区剩余空间情况
setlocal EnableDelayedExpansion
echo.&echo.
echo        ╔══════════════════════════════╗
echo        ║        磁盘分区         磁盘卷标名      剩余空间(MB)       ║
echo        ║    _____________________________________________________   ║
for %%i in (C D E F G H I J K L M N O P Q R S T U V W X Y Z) do (
    if exist %%i:\ (
        for /f "tokens=3" %%j in ('dir /-c %%i:\') do set freesize=%%j
        if not "!freesize!"=="0" (
            set /a freesize=!freesize:~0,-3!/1049
            set freesize=       !freesize!
            set freesize=!freesize:~-7!
            for /f "tokens=3*" %%k in ('vol %%i:') do set volume=%%l
            set volume=                    !volume!
            set volume=!volume:~-20!
            echo        ║           %%i: !volume!     !freesize!              ║
        )
    )
)
endlocal
echo        ╚══════════════════════════════╝
echo.&echo.&echo.&echo.
echo                                                按任意键返回上一步...
pause>nul
goto input_destination

rem  ========创建备份任务脚本程序,要考虑到生成多个批处理文件的情况=============
:build_backup
call :list
title 文件备份器-正在生成备份程序...
md "%ProgramFiles%\备份任务程序" 2>nul
set batch_directory=%ProgramFiles%\备份任务程序
attrib /s /d -r -h -s "%batch_directory%\*.*" 2>nul

:: 因为把所有的批处理内容只用一句 >"%batch_directory%\%name%_backup.cmd" 来接收,
:: 所以其中的括号都要用 ^ 来转义

(
echo @echo off
echo mode con cols=35 lines=10
echo color 1f
echo title 文件备份器-"%name%_backup"
echo ::        本程序由"文件备份器V2.4"生成  Code by JM  Renew on 2007-4-8 QQ:13132002
echo ::                 build on %date% %time:~0,-3% by %username%
echo.
echo ::    原理:比较原始文件和备份文件修改日期的早晚,如果原始文件修改时间晚于备份文件,
echo ::          则复制原始文件覆盖备份文件;如果时间没差别,则不作任何处理。
echo.
echo if not exist "%source%" ^(
echo title 文件丢失
echo color 0c
echo echo.
echo echo ___________________________________
echo echo.
echo echo 文件"%source%"
echo echo.
echo ecoh 不存在,可能已被改名、移动或者删除
echo echo.
echo echo ___________________________________
echo ping -n 5 127.1>nul
echo exit^)
echo md "%destination%" 2^>nul
)>"%batch_directory%\%name%_backup.cmd"

set xcopy_parameter=
if "%folder%"=="yes" (set xcopy_parameter=/e /s) else (goto file_backup)

(
echo set times=
echo setlocal enabledelayedexpansion
echo for /f "delims=" %%%%i in ^('xcopy /c /d /h /i /g /r %xcopy_parameter% /x /y "%source%" "%destination%"'^) do ^(
echo     if "%%%%i"=="复制了 0 个文件" ^(exit^) else ^(
echo         if not defined times call :head
echo         if ^^!file_time^^! lss %%%%~ti set file_time=%%%%~ti^&set file_route=%%%%~dpnxi
echo         if not "%%%%~ti"=="" ^(echo     %%%%~dpnxi    %%%%~ti^>^>"%destination%\%name_log%_log.log"
echo         ^) else ^(echo.^&echo                                                %%%%i^)^>^>"%destination%\%name_log%_log.log"
echo     ^)
echo     if "%%%%i"=="复制了 1 个文件" goto end
echo ^)

echo ^(
echo echo.
echo echo     最后更新的文件是:%%file_route%% ,更新操作发生在 %%file_time%% 。
echo ^)^>^>"%destination%\%name_log%_log.log"
echo :end
echo start "" "%destination%\%name_log%_log.log"
echo goto :eof
echo.
)>>"%batch_directory%\%name%_backup.cmd"
call :build_head
goto add_to_reg

:file_backup
(
echo xcopy /c /d /h /i /g /q /x /y "%source%" "%destination%"^|findstr /b /e /c:"复制了 0 个文件"^>nul^&^&goto :eof
echo echo.^>^>"%destination%\%name_log%_log.log"
echo for /f "skip=1 tokens=1,2" %%%%i in ^('dir /a-d /tw "%source%"^^^|find "-"'^) do ^(
echo     echo ^^^<%%date:~0,10%% %%time:~0,8%% 备份记录^^^> 文件最后一次更新时间:%%%%i %%%%j^>^>"%destination%\%name_log%_log.log"
echo ^)
echo start "" "%destination%\%name_log%_log.log"
)>>"%batch_directory%\%name%_backup.cmd"

:add_to_reg
cls
color 1f
title 文件备份器-开机自运行选项
echo.
echo                               ╭────────╮
echo           ╭─────────┤ 开机自运行选项 ├─────────╮
echo           │                  ╰────────╯                  │
echo           │        操作说明:                                      │
echo           │                                                        │
echo           │            本操作即将把备份任务加入到开机自运行        │
echo           │                                                        │
echo           │        选项中。若要取消开机自运行功能,请在"开始       │
echo           │                                                        │
echo           │        \运行"中输入"msconfig",打开"系统配置实用       │
echo           │                                                        │
echo           │        程序",在"启动"处取消以备份任务名称命名的       │
echo           │                                                        │
echo           │        启动项目,或者在注册表[HKEY_LOCAL_MACHINE\      │
echo           │                                                        │
echo           │        SOFTWARE\Microsoft\Windows\CurrentVersion\      │
echo           │                                                        │
echo           │        Run]下删除相应的字符串值。                      │
echo           │                                                        │
echo           ╰────────────────────────────╯
echo.
echo            接受请直接敲回车                                跳过请按 S
echo           ──────────────────────────────
echo.
set choice=
set /p choice=           请输入操作代码(S/回车):
if /i "%choice%"=="s" goto run_at

rem  ========在注册表中增添自启动项以便开机时自动备份=============
reg add HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run /v "%name%" /t REG_SZ /d "%batch_directory%\%name%_backup.cmd" /f >nul 2>nul

:run_at
:: 强制启用计划任务服务
sc config Schedule start= AUTO >nul 2>nul
sc start Schedule>nul 2>nul
rem  ==========导入at计划任务=========
for %%i in (%copytime%) do (
    at %%i /every:%copydate%  "%batch_directory%\%name%_backup.cmd" 2>nul
)
(
echo.&echo.
echo   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
echo.
echo       于%date% %time:~0,8%创建了备份任务
echo       备份对象:"%source%"
echo       备份文件保存位置:"%destination%"
echo       备份程序位置:"%batch_directory%\%name%_backup.cmd"
echo.
echo   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
echo.
echo ________________________________________________________________________________
)>>"%destination%\%name_log%_log.log"

cls
color 1f
title 文件备份器-备份中……
echo.&echo.&echo.&echo.&echo.&echo.
echo                               ╭────────╮
echo           ╭─────────┤  正在备份文件  ├─────────╮
echo           │                  ╰────────╯                  │
echo           │        操作说明:                                      │
echo           │                                                        │
echo           │            备份时间和文件大小、文件数量成正比,请      │
echo           │                                                        │
echo           │        耐心等待……                                    │
echo           │                                                        │
echo           ╰────────────────────────────╯
xcopy /c /h /i /g /q /r %xcopy_parameter% /x /y "%source%" "%destination%" 2>nul

::  添加当计划任务出错时提交报告的功能
:: --------------------------------------------------------------------
:: 当使用计划任务让系统自动运行一些命令或程序时,如果运行时发生错误,
:: 在系统的默认设置里,计划任务不会提交错误报告。
:: 此设置就是让计划任务在出现错误时弹出提示信息。
:: 要禁用此功能,请删除注册表中SchedulingAgent下的 NotifyOnTaskMiss
:: 默认不开通;若要开通,请去掉以下reg语句前的注释符号
:: --------------------------------------------------------------------
:: reg add HKLM\SOFTWARE\Microsoft\SchedulingAgent /v NotifyOnTaskMiss /t REG_DWORD /d 00000001 /f >nul 2>nul

cls
title 备份日志
echo.&echo.
type "%destination%\%name_log%_log.log"
echo.&echo.&echo.
echo                                                        按任意键继续...
pause>nul

cls
title 备份任务列表
echo.&echo.&echo.&echo.&echo.&echo.
echo ________________________________________________________________________________
echo.
for %%i in (%copytime%) do (
    echo          已经添加了每月^(周^) %copydate% 日 %%i 对"%source%"的备份任务
)
echo.
echo ________________________________________________________________________________
echo.
echo                     如要继续添加备份任务,请输入 B ,其他任意键退出...
echo.&echo.
set again=
set /p again=                             请选择下一步操作代码:
if /i "%again%"=="b" goto input_source
exit

rem  ========删除不再使用的文件或目录=============
:del_unused
:: 以下语句的作用是:如果停止了某项备份任务,则检查硬盘上由本程序生成的cmd文件中,
:: 不在at任务列表中的有哪些;如果有,则删除该cmd,同时删除注册表中对应的字符串值;
:: 如果没有,则不作任何删除操作;
:: 如果由本程序在%ProgramFiles%下创建的目录为空,则删除该目录
for %%i in ("%ProgramFiles%\备份任务程序\*_backup.cmd") do (
    at|find /i "%%i">nul || find /i "Code by JM" "%%i">nul && (
        del /a /f /q "%%i"
        reg delete HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run /v "%name%" /f >nul 2>nul
    )
)
if not exist "%ProgramFiles%\备份任务程序" goto :eof
rd "%ProgramFiles%\备份任务程序" 2>nul
goto :eof


:: ━━━━━━━━━━━━━━━━━以下代码为出错提示━━━━━━━━━━━━━━━━━

:system_error
cls
color 0c
title 文件备份器-操作系统不支持
echo.&echo.&echo.&echo.&echo.&echo.
echo                               ╭────────╮
echo           ╭─────────┤ 操作系统不支持 ├─────────╮
echo           │                  ╰────────╯                  │
echo           │                                                        │
echo           │                                                        │
echo           │         非常抱歉,该程序只能在XP环境下运行             │
echo           │                                                        │
echo           │                     程序即将退出...                    │
echo           │                                                        │
echo           ╰────────────────────────────╯
ping -n 4 127.1>nul && goto :eof

:popedom_error
cls
color 0c
title 文件备份器-权限不足
echo.&echo.&echo.&echo.&echo.&echo.
echo                               ╭────────╮
echo           ╭─────────┤    权限不足    ├─────────╮
echo           │                  ╰────────╯                  │
echo           │                                                        │
echo           │                                                        │
echo           │                                                        │
echo           │      非常抱歉,当前用户权限太低,无法运行本程序        │
echo           │                                                        │
echo           │      请换用具备管理员组权限的其他用户帐号来运行        │
echo           │                                                        │
echo           │                    按任意键退出...                     │
echo           │                                                        │
echo           ╰────────────────────────────╯
pause>nul
goto :eof

:subarea_noexist
cls
color 0c
title 文件备份器-磁盘 "%subarea%" 不存在
echo.&echo.&echo.&echo.&echo.
echo                               ╭────────╮
echo           ╭─────────┤ 磁盘分区不存在 ├─────────╮
echo           │                  ╰────────╯                  │
echo           │                                                        │
echo           │                                                        │
echo           │                盘符为 %subarea% 的磁盘分区不存在               │
echo           │                                                        │
echo           │             按任意键返回上一步重新选择路径             │
echo           │                                                        │
echo           ╰────────────────────────────╯
echo.
pause>nul
goto input_destination

:source_noexist
cls
color 0c
title 文件备份器-文件不存在
echo.&echo.&echo.&echo.&echo.
echo                               ╭────────╮
echo           ╭─────────┤   文件不存在   ├─────────╮
echo           │                  ╰────────╯                  │
echo           │                                                        │
echo           │                                                        │
echo           │                   要备份的文件不存在                   │
echo           │                                                        │
echo           │               按任意键返回上一步重新选择               │
echo           │                                                        │
echo           ╰────────────────────────────╯
echo.
pause>nul
goto input_source

:forbid_to_backup
cls
color 0c
title 文件备份器-禁止备份
echo.&echo.&echo.&echo.&echo.
echo                               ╭────────╮
echo           ╭─────────┤    禁止备份    ├─────────╮
echo           │                  ╰────────╯                  │
echo           │                                                        │
echo           │                                                        │
echo           │                  本程序不支持全盘备份                  │
echo           │                                                        │
echo           │               按任意键返回上一步重新选择               │
echo           │                                                        │
echo           ╰────────────────────────────╯
echo.
pause>nul
goto input_source

:forbid_to_build_1
cls
color 0c
title 文件备份器-禁止创建
echo.&echo.&echo.&echo.&echo.
echo                               ╭────────╮
echo           ╭─────────┤    禁止创建    ├─────────╮
echo           │                  ╰────────╯                  │
echo           │                                                        │
echo           │                                                        │
echo           │         为了数据的安全,请勿直接备份到根目录下         │
echo           │                                                        │
echo           │               按任意键返回上一步重新选择               │
echo           │                                                        │
echo           ╰────────────────────────────╯
echo.
pause>nul
goto input_destination

:forbid_to_build_2
cls
color 0c
title 文件备份器-禁止创建
echo.&echo.&echo.&echo.&echo.
echo                               ╭────────╮
echo           ╭─────────┤    禁止创建    ├─────────╮
echo           │                  ╰────────╯                  │
echo           │                                                        │
echo           │        警告:保存位置与要备份文件的位置路径相同        │
echo           │                                                        │
echo           │              或者位于要备份文件的某一目录下            │
echo           │                                                        │
echo           │            为了数据的安全,请重新选择保存位置          │
echo           │                                                        │
echo           │               按任意键返回上一步重新选择               │
echo           │                                                        │
echo           ╰────────────────────────────╯
echo.
pause>nul
goto input_destination

:destination_input_erro
cls
color 0c
title 文件备份器-路径输入错误
echo.&echo.&echo.&echo.&echo.
echo                               ╭────────╮
echo           ╭─────────┤  路径输入错误  ├─────────╮
echo           │                  ╰────────╯                  │
echo           │                                                        │
echo           │                                                        │
echo           │                   您的路径输入有错误                   │
echo           │                                                        │
echo           │              请在半角状态输入冒号和反斜杠              │
echo           │                                                        │
echo           │               按任意键返回上一步重新选择               │
echo           │                                                        │
echo           ╰────────────────────────────╯
echo.
pause>nul
goto input_destination

:date_error
cls
color 0c
title 文件备份器-日期输入错误
echo.&echo.
echo                               ╭────────╮
echo           ╭─────────┤  日期输入错误  ├─────────╮
echo           │                  ╰────────╯                  │
echo           │                                                        │
echo           │                   您的日期输入有错误                   │
echo           │                                                        │
echo           │                                                        │
echo           │        1. 日期不能字母和数字混用;                     │
echo           │                                                        │
echo           │        2. 单个的数字式日期不能大于31;                  │
echo           │                                                        │
echo           │        3. 字母式的日期只能是 M,T,W,Th,F,S,Su 中的      │
echo           │                                                        │
echo           │    任意几个,不区分大小写;                            │
echo           │                                                        │
echo           │        4. 日期之间只能用逗号分隔。                     │
echo           │                                                        │
echo           │                                                        │
echo           │               按任意键返回上一步重新选择               │
echo           │                                                        │
echo           ╰────────────────────────────╯
pause>nul
goto input_date

:time_error
cls
color 0c
title 文件备份器-时间输入错误
echo.&echo.&echo.&echo.&echo.
echo                               ╭────────╮
echo           ╭─────────┤  时间输入错误  ├─────────╮
echo           │                  ╰────────╯                  │
echo           │                                                        │
echo           │                                                        │
echo           │                   您的时间输入有错误                   │
echo           │                                                        │
echo           │小时数不能大于23,分钟数不能大于59,每个时间点用空格分隔│
echo           │                                                        │
echo           │               按任意键返回上一步重新选择               │
echo           │                                                        │
echo           ╰────────────────────────────╯
echo.
pause>nul
goto input_time

:name_exist
cls
color 0c
title 文件备份器-同名程序 "%name%_backup.cmd" 已经存在
echo.&echo.&echo.&echo.&echo.
echo                               ╭────────╮
echo           ╭─────────┤  存在同名程序  ├─────────╮
echo           │                  ╰────────╯                  │
echo           │                                                        │
echo           │                                                        │
echo           │ "%ProgramFiles%\备份任务程序"下已存在同名的批处理程序│
echo           │                                                        │
echo           │               按任意键返回上一步重新选择               │
echo           │                                                        │
echo           ╰────────────────────────────╯
echo.
pause>nul
goto input_name

:: ━━━━━━━━━━━━━━━━━以下代码为被调用的子过程━━━━━━━━━━━━━━━━━

rem  ========查看保存位置下的内容以决定 追加/覆盖/重新选择 等操作========
:view_directory
explorer "%destination%"
goto :eof

rem  ========简化每天都需要备份时的操作========
:all_date
set copydate=1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31
goto input_time
goto :eof

rem  ========查看备份脚本程序========
:view_batch
explorer "%ProgramFiles%\备份任务程序"
goto input_source
goto :eof

rem  ========显示备份清单========
:list
cls
color 1f
title 文件备份器-备份清单
echo.
echo ________________________________________________________________________________
echo.
echo                         备份任务名称:"%name%"
echo.
echo                         要备份的文件:"%source%"
echo.
echo                         保存位置:"%destination%"
echo.
echo                         备份日期: %copydate%
echo.
echo                         备份时间:%copytime%
echo.
echo ________________________________________________________________________________
echo.
goto :eof

rem  ========日志里的更新列表头========
:build_head
(
echo :head
echo set times=1
echo ^(
echo echo _____________________________________________________________________________________
echo echo.
echo echo *更新列表^^^(%%date:~0,10%% %%time:~0,8%%^^^):
echo echo.
echo ^)^>^>"%destination%\%name_log%_log.log"
echo goto :eof
)>>"%batch_directory%\%name%_backup.cmd"
goto :eof
  更新历史:
更新历史:

07.4.7~8

     搁置了将近半年之久,再次更新代码。此次更新动作较大,主要做了以下改动:
         ① 考虑到恢复原始文件属性的操作有很大风险(比如丢失了属性配置batch
   文件会导致无法恢复文件的原始属性,从而给文件读写带来无尽的麻烦),因此,
   取消了对备份后文件加上"系统+只读"属性的操作;相应地,一并取消了恢复备份
   的脚本程序,使得备份效率大为提升;
     ② 修改了不能正确删除注册表中相关项目的bug;
     ③ 优化了日期及时间的输入检测功能,备份速度有所提高;
     ④ 全面精简了代码;
     ⑤ 把更新历史从代码中分离出来,减少了cmd文件的体积。
     此为V2.4;若功能方面没有什么大的bug,将作为final版推出,不再更新。

06.11.4

         增加了记录备份文件更新列表的功能,进一步完善日志功能;

06.10.19

         因at命令只能以管理员权限运行,此次更新增加了用户权限的验证;添加了
     xcopy的/c参数,使得复制出错的时候(尽管出现这种情况的几率非常低),能备份
     尽可能多的文件;精简了部分代码;

06.9.14

         对提取文件属性的代码做了优化,使得生成备份批处理的效率大大提高,
     感谢pengfei提供代码;修改了几处错误和疏漏;对代码进行分块放置以便日后
     的维护;此为V2.3

06.9.3

         由于上次精简过度,代码运行会出错,今天修改了一处致命错误,感谢
     pengfei的测试;增加了一些操作提示和出错检测;

06.8.5

         添加了备份空目录的参数,精简了部分代码;
06.8.1

         实现了用同一条命令复制文件和文件夹;修正了几处错误;
06.7.29

         精简了获取属性的代码,感谢willsort提供;
06.7.28
         完善了对备份后的文件进行恢复的操作,使得恢复操作对文件或者文件夹
     都适用;此为V2.2

06.7.1
         完善了对日期的检测;
06.6.29
         增加了恢复文件的功能;对生成后的文件的属性进行了调整;此为V2.1;
06.6.20
         对显示各分区磁盘剩余空间的代码进行了修改,只显示磁盘的剩余空间,
     而不会画蛇添足地显示光盘剩余空间;
06.6.15
         增加了日期和时间输入错误检测功能(感谢bagpipe提供代码);
06.6.12
         修改了查询各分区剩余空间的代码,当磁盘卷标名为中文时也能准确排版。
     感谢willsort作深入分析并提供代码;当备份任务创建后,能自动打开备份后
     的文件夹和创建日志,以便查看备份创建结果;彻底删除无用文件;精简了部
     分代码;
06.6.10
         修正了一处错误;精简了部分代码;
06.6.9  
         更改备份日志代码,将使备份日志体积减少近一半;更改了实现文件名自动
     完成这一功能的功能键(感谢electronixtar的提醒),但需要注册表中的特定键
     值为默认设置(有关讨论请参考http://www.cn-dos.net/forum/viewthread.php?
     tid=21091&fpage=1);
06.6.6
        修改了部分代码,使得当需要每天备份的功能时,避免了烦琐的输入;增加
    了文件名自动完成的功能(感谢willsort提出设想并提供代码);此为V1.9;
06.6.4  
        增加了如下功能:当保存备份文件时,如果要对文件夹进行追加或者覆盖等
    操作,可先查看该文件夹下的内容再作决定;补充了备份风险提示;
06.6.3  
        对备份后文件的保存位置这部分代码进行了修改,使得程序能自动适应备份
    对象为文件和文件夹两种情况,使备份后文件夹的目录结构得到保持,感谢
    willsort提供代码;当备份文件即将保存到一个已经存在的目录下时,增加了允
    许追加至该目录的选择;
06.6.2
        添加和修改了了如下功能:可以选择在开机时是否自动运行备份任务程序;
    开始运行本程序或者停止某项备份任务时,自动删除当前计划任务中不再使用的
    备份任务程序,并删除对应的注册表键值,以减少系统垃圾;更改了备份任务程
    序的保存位置;去除了盘符小写转换为大写的鸡肋代码;增强了路径输入为空时
    的检测(感谢willsort提供代码);修改了几处错误;精简了部分代码,此为V1.8;
06.5.31   
        在注册表中( 位置是:HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\
    CurrentVersion\Run) 增添了开机自动运行备份程序的键值( 以备份任务名称作
    为键值) ,尽可能减少错过备份的情况;如果更新了内容,则备份完毕后自动打
    开备份日志;修正了几处错误;此为V1.7;
06.5.30   
        完善了备份流程,在列出创建备份任务的清单时,可更改备份任务内容;在
    创建备份任务的同时,强制启动计划任务服务,并立即作复制操作;显示各磁盘
    分区剩余空间情况的时候,增加了显示磁盘卷标名的功能;更改了注意事项界面
    中的前景色和背景色,使色调显得明快而柔和;
06.5.28   
        增加了在每周的指定日期进行备份的功能;添加了当计划任务出错时提交报
    告的功能;完善了日志记录功能,只有当文件更新时才会改写日志;完善了注意
    事项中的内容;增加了删除所有计划任务的功能;此为 V1.6 ;
06.5.26   
        增加了不允许把保存路径设置为与源文件路径相同、或者为源文件某一目录
    的功能;添加了注意事项提示功能;修正了几处错误;部分代码参照中国DOS 联
    盟论坛(http://www.cn-dos.net/forum) 网友bagpipe所发帖子,使一些代码得
    到精简;此为V1.5;
06.5.25   
        增加了把备份文件的保存目录拖曳到窗口执行的功能;增加了批量停止指定
    备份任务的功能;修改了几处错误;精简了部分代码;此为V1.4;
06.5.24   
        增加了把要备份的文件拖曳到窗口执行的功能;感谢中国DOS 联盟论坛
    (http://www.cn-dos.net/forum)版主willsort提供代码;此为V1.3;
06.5.23   
        修正了一处关键错误,使得备份能顺利进行下去;在中国DOS 联盟论坛
    (http://www.cn-dos.net/forum)版主willsort等网友的热心帮助下,增强了程
    序输入错误检测能力,并修正了一些拼写错误,在此深表谢意;
06.5.22   
        修改了显示各分区剩余空间的代码,使显示界面的框线自动适应剩余空间条
    目下不同长度的字符;
06.5.21   
        增添了停止指定备份任务的功能,使本程序的功能进一步完善;增添了将备
    份后的文件设置为" 系统+ 只读" 属性的功能,从而在一定程度上提高了备份后
    的文件的安全;修正了几处错误;优化了部分代码;此为V1.2;
06.5.20   
        头两天的算法存在备份不完全的弊端,今天把copy命令更改为xcopy 命令,
    从而使本程序能够备份指定目录下除空目录之外的所有文件( 包括目录之下还有
    子目录、子目录内含有文件的文件嵌套) ,并使代码得到了精简;头两天的代码
    生成备份任务批处理的时候,因为自动命名的程序名称是固定的,如果有不同的
    备份任务的话,最后一次任务将把上一次的任务删除,今天把备份任务的命名改
    为手动指定;增添了多次添加备份任务的功能;此为V1.1;
06.5.19   
        增加了系统检测功能,使得该程序只能运行于XP操作系统下;编写输入错误
    检测代码,使输入错误能得到及时更改;统一了交互界面,看上去更加美观;本
    来想增加指定每周的某几天进行备份操作的功能,但是一直未能实现,只好暂时
    放弃,留待下几个版本解决;优化了部分冗余代码;
06.5.18   
        在对本人电脑上重要资料进行备份的时候,深感手工备份的烦琐,而网上的
    备份软件又有诸多限制,正好本人在自学DOS 批处理编程,于是花了半天的时间
    来构思本程序的核心功能,编写初步代码;此为V1.0;
  注:
  1.因为还没找到显示比例为4:3的电脑显示器,只能将就我的显示比例了(分辨率为1280×768);
  2.自动完成文件名这一功能非常实用,但尚有不完善之处,详情请看46楼,请各位高手帮忙解决;
  3.当xcopy加上/e参数时,复制文件的时候会把文件所在目录下的文件夹(不包含其中的文件)都复制过去;当备份的是文件夹且结构为"文件夹1-文件夹2-文件夹3-文件"的时候,会去掉最上层的文件夹;百思不得其解;
  4.更新之处请看更新历史;
      5.[求助]有没有谁装了2K的系统,如果有的话,请帮忙测试一下在2K下能不能通过(要把:check_system这一节代码去掉),有测试过的请帮忙回帖反馈一下。目前我只知道在显示%date%和%time%的时候会不一样;
  6.如果有什么地方需要完善的,欢迎跟帖;

  有关本程序的讨论主要有:

[1]什么情况下该使用变量延迟?
http://www.cn-dos.net/forum/viewthread.php?tid=20733

[2]监视文件操作的批处理该如何编写?       
http://www.cn-dos.net/forum/viewthread.php?tid=20732

[3]如何用固定长度显示长度不一致的字符?
http://www.cn-dos.net/forum/viewthread.php?tid=20734

[4]怎样去掉DOS窗口的下拉条
http://www.cn-dos.net/forum/viewthread.php?tid=20040

[5]at命令中为什么无法显示%username%
http://www.cn-dos.net/forum/viewthread.php?tid=20238

[6][部分已结]如何显示磁盘的剩余空间?
http://www.cn-dos.net/forum/viewthread.php?tid=19738

[7]长文件名如何应用于批处理文件中
http://www.cn-dos.net/forum/viewthread.php?tid=19223

[8][求助]在2K环境下date命令的运行结果
http://www.cn-dos.net/forum/viewthread.php?tid=20043

[9]如何检测文件名带空格的文件夹是否存在
http://www.cn-dos.net/forum/viewthread.php?tid=19836

[10]怎样复制指定内容到指定文件里去
http://www.cn-dos.net/forum/viewthread.php?tid=19855

[11][已结]dir命令查询目录找不到文件是什么原因
http://www.cn-dos.net/forum/viewthread.php?tid=19803

[ Last edited by namejm on 2007-4-8 at 11:18 AM ]
附件 1: 文件备份器(Final).rar (2007-4-9 00:20, 117.32 K,下载次数: 328)

作者: willsort     时间: 2006-5-23 01:47
Re namejm:

      很不错的一个批处理脚本,可以看出兄十分用心。因此我有一个建议,将此主题改造为关于“文件自动备份批处理脚本”的原创主题,首帖转贴最新的源码,回复帖对其中涉及的若干细节和问题进行讨论。这要求转移和合并你过去发表的一些主题帖,因此需要征得你的同意。

      关于at3命令的执行问题,因为代码尚没有看完,因此无法发表什么意见,仅推测似与其所对应的备份脚本有关,因此需要贴出这段批处理的代码。

      另外,仅就以下引用自源码中的一节略作讨论:

  Quote:
set /p source=           请输入要备份文件的路径:
:: 这里可以提示直接将备份目标拖拽入运行窗口中,即可获得源路径

for /f "delims=:\" %%i in ("%source%") do set subarea1=%%i
:: 似乎是获取源的盘符,为何不使用 set subarea1=%source:~0,1%

if not "%source%"=="" set source=%source%
:: 此句意义未明,尚请指教
:: 如果是将路径格式化,需要使用for %%p in ("%source%") do set source=%%~fp

if "%source%"=="" goto input_source
:: 建议将直接按下回车的选择(即%source%为空)分配给使用频率高的操作
if "%source%"=="0" exit
if "%source%"=="1" goto backup_task

echo "%source%"|find "%subarea1%:\" > nul
if "%ERRORLEVEL%"=="1"  goto input_source
:: 判断路径中是否含有盘符?可否用 if "%source:~1,2%"==":\"

if "%source%"=="%subarea1%:\" goto forbid
:: 判断路径是否为根路径?当 source 为 C:\\ 或者 C:\. 时将不起作用

if not exist "%source%" goto source_noexist
goto input_object
:: object 的含义为对象,与备份目标有歧义,不如改为target或destination

[ Last edited by willsort on 2006-5-23 at 01:48 ]
作者: bagpipe     时间: 2006-5-23 12:30
LZ真是有耐心,这么长,比我毕业论文都长,佩服,佩服..........正如WILLSOFT所说代码没有看完呢还得慢慢消化一下才可以的............
作者: Climbing     时间: 2006-5-23 13:05
我觉得at出现的错误跟批处理没有太大的关系,有可能是有其它方面的原因。

从楼主的批处理来看,只要有一个at计划正常运行了,那么其它的也应该没有问题。

对楼主的耐心表示敬意,不过,如果你仅仅是为了实现文件备份功能而写这个批处理,实在不如引进一些第三方工具来得简单,例如:SecondCopy,或者同步软件CmdSync等 。当然,个人的环境不同,所以方法也不同,我的仅仅是建议。
作者: doscc     时间: 2006-5-23 14:11
同意4楼的建议!

对楼主的耐心表示敬意

虽然脚本可以帮我们完成一些 大量重复的工作!
但是有时用一些第三方软件也不错的.
作者: namejm     时间: 2006-5-23 14:18
to willsort 版主:
我不清楚你进行"转移和合并你过去发表的一些主题帖"这个操作的时候需要什么条件,我十分高兴这个脚本能得到大家的进一步完善,请版主按照你的想法编辑就是了,有什么地方需要我做的,我尽量配合.谢谢willsort.
报告一下问题所在:
刚才突然回想起手动执行生成的计划任务批处理,屏幕显示"……是否改写?(YES or NO or All)"(大意如此,现在时间匆忙,没来得及细看),看来是因为at是后台运行的,对需要手动确认的命令不会作任何提示,所以造成了cmd.exe和xcopy.exe进程一直存在,而备份操作没有执行的现象.
现在在xcopy一句后加上 /y 参数,问题解决.
各位的回复都看了一下,看来这个脚本还有很多需要完善的细节.因为马上要上班去了,没时间一一回复,只有等下了班再来回答,请各位原谅.同时,也请大家继续挑里面的毛病,特别是看有有些地方没有什么更好的解决办法.在此谢过各位.
作者: namejm     时间: 2006-5-23 18:40
感谢willsort版主的点评,以下是我的一些想法:
"set /p source=           请输入要备份文件的路径:
:: 这里可以提示直接将备份目标拖拽入运行窗口中,即可获得源路径"
——居然还可以直接拖过去就能显示路径,呵呵,意外收获,在此谢过willsort。如果路径带有空格,直接拖过去的话,会自动在路径首尾添加引号,而当初为了照顾手工输入带空格的路径,下面的变量引用都是加了引号的,如果提示用拖曳的办法的话,会造成程序出错。如果不允许手工输入只允许拖曳的话,再去掉变量引用的引号,应该可以解决这个矛盾。暂时还不好取舍。

"for /f "delims=:\" %%i in ("%source%") do set subarea1=%%i
:: 似乎是获取源的盘符,为何不使用 set subarea1=%source:~0,1%"
——如果用拖曳的方法输入的路径带空格的话,只能取到前引号。如果采用上一条的方案,只允许拖曳的话,会导致错误,看来拖曳的方法挺容易出错的。

"if not "%source%"=="" set source=%source%
:: 此句意义未明,尚请指教
:: 如果是将路径格式化,需要使用for %%p in ("%source%") do set source=%%~fp"
——说实话,这句我也不太弄得明白,是我从深山红叶光盘的批处理程序中抄袭过来的,当时以为是获取键盘输入的一种格式,没有细想。

"if "%source%"=="" goto input_source
:: 建议将直接按下回车的选择(即%source%为空)分配给使用频率高的操作
if "%source%"=="0" exit
if "%source%"=="1" goto backup_task"
——我的本意是检测是否有输入内容,如果没有的话,则强制输入,不允许跳过,感觉这样处理比较好,暂时不打算更改此处代码。

"echo "%source%"|find "%subarea1%:\" > nul
if "%ERRORLEVEL%"=="1"  goto input_source
:: 判断路径中是否含有盘符?可否用 if "%source:~1,2%"==":\" "
——同上面的道理,在拖曳输入的时候,只能取到前引号。


"if "%source%"=="%subarea1%:\" goto forbid
:: 判断路径是否为根路径?当 source 为 C:\\ 或者 C:\. 时将不起作用"
——当时没有考虑到这种情况,多谢版主提醒,现在在后面增加两行代码,应该可以避免这个错误:
if "%source%"=="%subarea1%:\\" goto forbid
if "%source%"=="%subarea1%:\." goto forbid

"if not exist "%source%" goto source_noexist
goto input_object
:: object 的含义为对象,与备份目标有歧义,不如改为target或destination"
——说起来惭愧,对E文我一向比较头疼,所以经常会闹笑话。在新的代码里已经改过来了。多谢指正。

以下是修改过的代码:

[ Last edited by willsort on 2006-5-24 at 01:42 ]
作者: namejm     时间: 2006-5-23 18:54


  Quote:
Originally posted by Climbing at 2006-5-23 13:05:
对楼主的耐心表示敬意,不过,如果你仅仅是为了实现文件备份功能而写这个批处理,实在不如引进一些第三方工具来得简单,例如:SecondCopy,或者同步软件CmdSync等 。当然,个人的环境不同,所以方法也不同,我的仅仅是建议。

多谢老兄提供了这两个程序的线索,网上搜索了一下,它们的功能令人怦然心动。
但是有两个缺陷:1.正如我在这个脚本程序的更新历史里所说的那样,“网上的备份软件有诸多限制”,SecondCopy有30天免费使用期的限制,像我等不会破解之道的菜鸟,拿来使用30天之后,可能又得把系统时间往前调N天(还不一定有效),或者再手工备份,而网上的注册码都是过了期的,破解的似乎也没有;2.都是E文的。这个一直是令我很头疼的事情。虽然知道不多懂点E文在网络里不好混,在现实生活中也混不好,但是自己专业的限制,大学毕业之后就没多少心思再在E文上下工夫,所以我用的软件要么是国人开发的,要么就是汉化过的,可怜:(
综合以上原因,我决定还是自己编一个脚本程序,一来可以练技术,二来也可以拿来给我那些比我更菜的朋友们用。苦笑ing……
作者: willsort     时间: 2006-5-24 02:47
Re namejm:

      我已经将主题首帖作了一些改动,包括标题的修改和正文内容顺序的调整。

      原来试图将所有兄所发的与本程序有关的讨论主题合并到这里来,却发现兄对这个脚本下了不少功夫,竟然发现了十数个主题与此相关,如此一来,合并工作量大不说,也会导致许多原来相关性不大的讨论主题夹杂在同一主题中,反而降低了主题的作用。因此,最终决定只在首帖中给出所有相关讨论主题的链接以供查阅索引。

      其次,将兄7楼中的代码转移到首帖中,这是考虑到以下原因:一是因为代码体积过大,如果出现多个差异不大的版本,将会降低页面的打开速度、增加用户的阅读时间,同时耗费更多的论坛空间和时间资源;二是因为我们发表程序的原则是尽可能让用户以最方便的方式获取最新的版本,而如果将新版本更新在回复帖中,可能需要滚动甚至翻页才能得到,那就抬高了推广的门槛。因此,建议兄发布新版程序时,也能将代码编辑到首帖中。

      再次,关于我引用的那一小节,你的两难是可以解决的。用户可以拖拽备份源,也可以直接输入源路径(绝对路径或者相对路径),无论它是否含有引号,无论它是否含有非标准的路径引用方式(C:\\,C:\.\),我们都可以通过对路径串进行预先的格式标准化处理来解决这些不兼容的问题。以下的语句可以剔除路径中可能存在的引号,将相对路径转换为绝对路径,将非标准路径转换为标准路径(C:\\-->C:\),并判断路径是否有效地存在,是否是根路径。 不过它仍无法抵抗路径中出现的非法字符(>|),不知其他兄弟还有什么更好的办法没有?

      最后,不知兄使用何种环境编写代码?但从注释的宽度达到114来看,兄或许使用的是宽屏显示器,所以不虞注释的换行浏览问题。然而根据论坛和我的系统环境(17"+XP+EditPlus2)中贴出的代码来看,无论是否开启自动换行功能,注释的宽度过大都影响了代码的可阅读性。
set _src=
for %%p in ("%source%") do if exist %%p set _src=%%~fp
if "%_src%"=="" for %%p in (%source%) do if exist %%p set _src=%%~fp
if "%_src:~1,2%"==":\" goto forbid
set source=%_src%
[ Last edited by willsort on 2006-5-24 at 02:54 ]
作者: namejm     时间: 2006-5-24 12:48


  Quote:
Originally posted by willsort at 2006-5-24 02:47:
Re namejm:

        最后,不知兄使用何种环境编写代码?但从注释的宽度达到114来看,兄或许使用的是宽屏显示器,所以不虞注释的换行浏览问题。然而根据论坛和我的系统环境(17"+XP+EditPlus2)中贴出的代码来看,无论是否开启自动换行功能,注释的宽度过大都影响了代码的可阅读性。

老大果然一眼看出问题的所在,我用的正是宽屏电脑,14''+XP,分辨率为1280×768,以前在学做网页的时候就因为宽屏的原因与标准的4:3屏幕不一致而痛苦不堪,现在居然把这个细节给搞忘记了,真是一语惊醒梦中人,看来得找个4:3的显示器来修改.
最初不是为了编这个脚本才发的帖子,而是因为在做光盘的时候,要从光盘中提取指定的E书到电脑上.随着兴趣的越发浓厚,而对批处理的热情一发不可收拾,在自己的电脑上捣鼓了不少脚本来增强系统的功能,自我娱乐.刚下班回来,还有点头昏脑胀,先睡个午觉,晚上下班回来再回复,请各位原谅.
作者: namejm     时间: 2006-5-24 17:32


  Quote:
Originally posted by willsort at 2006-5-24 02:47:
Re namejm:

     再次,关于我引用的那一小节,你的两难是可以解决的。用户可以拖拽备份源,也可以直接输入源路径(绝对路径或者相对路径),无论它是否含有引号,无论它是否含有非标准的路径引用方式(C:\\,C:\.\),我们都可以通过对路径串进行预先的格式标准化处理来解决这些不兼容的问题。以下的语句可以剔除路径中可能存在的引号,将相对路径转换为绝对路径,将非标准路径转换为标准路径(C:\\-->C:\),并判断路径是否有效地存在,是否是根路径。 不过它仍无法抵抗路径中出现的非法字符(>|),不知其他兄弟还有什么更好的办法没有?

能不能把路径用for来解析,如果有非法符号就跳转到警告界面?
作者: namejm     时间: 2006-5-24 23:54


  Quote:
Originally posted by willsort at 2006-5-24 02:47:
Re namejm:

set _src=
for %%p in ("%source%") do if exist %%p set _src=%%~fp
if "%_src%"=="" for %%p in (%source%) do if exist %%p set _src=%%~fp
if "%_src:~1,2%"==":\" goto forbid
set source=%_src%

把上面这段代码压缩成一句插入,测试了一下,觉得没什么问题,已经更新到脚本里去了,更新位置如下:
set source=
set /p source=           请输入要备份文件的路径:
for %%p in (%source%) do set source=%%~fp
for /f "delims=:\" %%i in ("%source%") do set subarea1=%%i
发现个问题,看来还得改动输入提示
title 请输入源文件路径
echo                               ╭────────╮
echo           ╭─────────┤选择要备份的文件├─────────╮
echo           │                  ╰────────╯                  │
echo           │        操作说明:                                      │
echo           │                                                        │
echo           │            本程序能把指定文件在指定时间内备份          │
echo           │                                                        │
echo           │        到指定位置。请把要备份的文件拖曳至本窗          │
echo           │                                                        │
echo           │        口(推荐做法),或者手工输入需要备份文件          │
echo           │                                                        │
echo           │        的完整路径(带空格的路径需在首尾加半角           │
echo           │                                                        │
echo           │        状态下的双引号;请勿输入非法字符;否则          │
echo           │                                                        │
echo           │        会产生无法预料的错误),然后回车确认。           │
echo           │                                                        │
echo           ╰────────────────────────────╯
echo.
echo            查看已存在的备份任务请按 1                      退出请按 0
echo           ──────────────────────────────
([code]与[code]之间的内容无法再应用字符颜色设置,不能醒目地标注出来,挺遗憾的)

[ Last edited by namejm on 2006-5-25 at 13:28 ]
作者: willsort     时间: 2006-5-25 00:12
Re namejm:

      问题的关键在于我们不能确定路径串的前后是否存在引号,所以不能贸然决定是否使用引号包含路径串,所以无法约束其中的非法字符。这我曾在[1]中作过类似的讨论,目前没有很好的解决办法。

      而任何对路径串进行探测和分析的语句(无论echoif、for),都要求命令行中出现路径串本身,而如果未受约束的非法字符显然会破坏命令行的正常秩序。甚至可能不会出现语法错误的提示,而意外地产生一些垃圾文件。

      在你现在的代码中,如果某些用户为了安全起见而将含空格路径用引号引起,那么代码显然会语法错误而中止。而目前为止,我们测试的仍只是善意用户的合法行为,还没有真正进行一些非善意的极限边界测试。

      所以说,要编制一个“健壮性”很强的代码是很困难的,尤其是在自由灵活的批处理中。

[1][讨论]批处理编程的异类: if语句中防空字符的选择
http://www.cn-dos.net/forum/viewthread.php?tid=12388#pid100419
作者: namejm     时间: 2006-5-25 18:32


  Quote:
Originally posted by willsort at 2006-5-24 02:47:
Re namejm:
以下的语句可以剔除路径中可能存在的引号,将相对路径转换为绝对路径,将非标准路径转换为标准路径(C:\\-->C:\),并判断路径是否有效地存在,是否是根路径。


set _src=
for %%p in ("%source%") do if exist %%p set _src=%%~fp
if "%_src%"=="" for %%p in (%source%) do if exist %%p set _src=%%~fp
if "%_src:~1,2%"==":\" goto forbid
set source=%_src%


以上的代码我插入到
set source=
set /p source=           请输入要备份文件的路径:


if not "%source%"=="" set source=%source%
if "%source%"=="" goto input_source
if "%source%"=="0" exit
if "%source%"=="1" goto backup_task

之间,并不能剔除带空格路径中的前后引号,而是跳转到禁止全盘复制的界面,难道是我插入的位置错了吗?

[ Last edited by namejm on 2006-5-25 at 22:38 ]
作者: willsort     时间: 2006-5-25 22:30
Re namejm:

      很抱歉!问题出在if "%_src:~1,2%"==":\" goto forbid句上,这句代码是我在完成路径测试后,转贴前临时插入进去的,因未经测试而导致出错!将它改为if "%_src:~1,3%"==":\" goto forbid可以解决问题。

     但以上代码还无法完善解决不存在文件及文件夹路径串的问题,将代码[1]替换为代码[2]可以解决这个问题。当然,新代码仍然无法防御“<|>”这些非法字符。

[1]Old code
set /p source=           请输入要备份文件的路径:
for %%p in (%source%) do set source=%%~fp
for /f "delims=:\" %%i in ("%source%") do set subarea1=%%i
if not "%source%"=="" set source=%source%
if "%source%"=="" goto input_source
if "%source%"=="0" exit
if "%source%"=="1" goto backup_task
echo "%source%"|find "%subarea1%:\" > nul
if "%ERRORLEVEL%"=="1"  goto input_source
if "%source%"=="%subarea1%:\" goto forbid
if "%source%"=="%subarea1%:\\" goto forbid
if "%source%"=="%subarea1%:\." goto forbid
if not exist "%source%" goto source_noexist
goto input_destination
[2]New code
set _i=
set source=
set /p source=           请输入要备份文件的路径:
for %%s in (%source%) do set /a _i+=1
if "%_i%"=="1" for %%p in (%source%) do set source=%%~p
:: 以上两句为判断%source%中是否存在引号,有则剔除
if "%source%"=="" goto input_source
if "%source%"=="0" goto :eof
if "%source%"=="1" goto backup_task
if not exist "%source%" goto source_noexist
for %%p in ("%source%") do if "%%~fp"=="%%~dp\" goto forbid
goto input_destination

作者: namejm     时间: 2006-5-25 23:33


  Quote:
Originally posted by willsort at 2006-5-25 22:30:
Re namejm:

      set _i=
set source=
set /p source=           请输入要备份文件的路径:
for %%s in (%source%) do set /a _i+=1
if "%_i%"=="1" for %%p in (%source%) do set source=%%~p
:: 以上两句为判断%source%中是否存在引号,有则剔除
if "%source%"=="" goto input_source
if "%source%"=="0" goto :eof
if "%source%"=="1" goto backup_task
if not exist "%source%" goto source_noexist
for %%p in ("%source%") do if "%%~fp"=="%%~dp\" goto forbid
goto input_destination

当把程序放在带空格的目录下执行时,当输入的路径为当前盘符+冒号的时候,并不能禁止全盘复制.而放到不带空格的目录下执行,或者是输入的路径为任意盘符+冒号+\的时候,则没问题,不知道是为什么.

[ Last edited by namejm on 2006-5-26 at 00:12 ]
作者: willsort     时间: 2006-5-26 09:02
Re namejm:

      这其中的原因在于,路径中的单纯使用盘符+冒号就意味着引用的是所指定磁盘的当前路径。所以在命令行直接使用盘符+冒号,会跳转到所指定磁盘的当前路径,而并非一定是根路径。

      所有存在的磁盘都有当前路径,并且同时有效;当我们未用cd或其它方式改变它时,通常为根路径。使用cd "d:\Program files"会改变D盘的当前路径,而不论当前盘是否是D盘;也而使用copy c:*.* d:会将C盘当前路径下所有文件拷贝到D盘当前路径下,而不论当前处于哪个盘。

      这应该算是一个固有的路径引用技巧,从DOS到CMD一直存在,如同. 和..一样。如果你想将d:转义为d盘根路径,相当于改变了命令行的固有约定,反而会对某些人造成困扰。我的新代码中有意测试了非当前盘的当前路径非根路径时的表现(E盘下测试当前路径为“C:\Documents and Settings”的C盘),结果我是满意的,它没有跳到forbid。
作者: willsort     时间: 2006-5-26 23:21
Re namejm:

      根据bagpipe兄在[1]中的提示,将剔除引号的两句代码改为一句,想来自己也曾有过%大于"大于^的优先级推测,却不知灵活运用,而在各种for/if结构间打转,甚感惭愧!

      在此多谢bagpipe兄赐教了!
set source=%source:"=%
[1]如何从用户传入的参数中去掉引号?
http://www.cn-dos.net/forum/viewthread.php?tid=20838&fpage=1
作者: namejm     时间: 2006-5-27 00:04
已经看到了bagpipe兄发的帖子,已经更新了XP文件备份器相关部分的代码,在此感谢两位高手.
作者: 无奈何     时间: 2006-5-27 00:18
To willsort
关于去除参数中首尾的双引号,好象记得与兄一起讨论过。
见:http://www.cn-dos.net/forum/viewthread.php?tid=17785
第 5 楼 1、项。
作者: namejm     时间: 2006-5-27 09:13    标题: [求助]怎么提取at命令中"命令行"栏目下的路径?

想把at命令中"命令行"栏目下的路径提取出来,先把at命令结果倒出到一文本文件中,发现格式如下:


状态 ID     日期                    时间          命令行
-------------------------------------------------------------------------------
        1   每月执行日期: 1 2 3 4 5 6 7...12:40         C:\WINDOWS\system32\家易理财数据备份.bat
        2   每月执行日期: 1 2 3 4 5 6 7...19:00         C:\WINDOWS\system32\家易理财数据备份.bat
        3   每月执行日期: 1 2 3 4 5 6 7...22:00         C:\WINDOWS\system32\家易理财数据备份.bat
其间有几个方块黑点(直接copy以上内容保存为文本文件不会出现,但是如果是用at>list.txt命令的话,会发现有方块黑点存在),不知道该格式的行与列是用什么分割的,导致无法用for命令来提取.
请问,我该怎么办?
如果能不产生临时文件就能提取的话,就更好了.

上述问题已经找到了一个解决办法,但是还不够完善,因为还是会产生临时文件,代码如下:
@echo off
del /q "%tmp%\list.txt">nul 2>nul
at>"%tmp%\list.txt"
(for /f "skip=2 tokens=4 delims=\" %%i in (%tmp%\list.txt) do (find /i "Code by JM" %systemroot%\system32\%%i >nul 2>nul && echo %%i由特定程序创建))
del /q "%tmp%\list.txt">nul 2>nul
pause>nul
[ Last edited by namejm on 2006-5-27 at 11:04 ]
作者: namejm     时间: 2006-5-27 09:36    标题: at命令为什么显示不出指定每周的某几天

用了如下命令:
at 22:00 /every:M,T,W c:\windwos\system32\家易理财数据备份.bat
用at命令查看清单,结果如下:

状态 ID     日期                    时间          命令行
-------------------------------------------------------------------------------
        1   每月执行日期: 1 2 3 4 5 6 7...12:40         C:\WINDOWS\system32\家易
理财数据备份.bat
        2   每月执行日期: 1 2 3 4 5 6 7...19:00         C:\WINDOWS\system32\家易
理财数据备份.bat
        3   每月执行日期: 1 2 3 4 5 6 7...22:00         C:\WINDOWS\system32\家易
理财数据备份.bat
        4   每月执行日期:...        22:00         c:\windwos\system32\家易理财数
据备份.bat

难道是我的电脑显示不正常吗?
(另:在论坛里用插入图象的功能,似乎只能插入网络上的图片,难道就不能插入本机上的吗?)
作者: namejm     时间: 2006-5-27 10:57    标题: 如何提取两个文本文件中有差别的内容?

假设1.txt中内容的格式如下:
状态 ID     日期                    时间          命令行
-------------------------------------------------------------------------------
        1   每月执行日期: 1 2 3 4 5 6 7...12:40         C:\WINDOWS\system32\家易
理财数据备份.bat
        2   每月执行日期: 1 2 3 4 5 6 7...19:00         C:\WINDOWS\system32\家易
理财数据备份.bat
2.txt的内容如下:
状态 ID     日期                    时间          命令行
-------------------------------------------------------------------------------
        1   每月执行日期: 1 2 3 4 5 6 7...12:40         C:\WINDOWS\system32\家易
理财数据备份.bat
        2   每月执行日期: 1 2 3 4 5 6 7...19:00         C:\WINDOWS\system32\家易
理财数据备份.bat
        3   每月执行日期: 1 2 3 4 5 6 7...22:00         C:\WINDOWS\system32\test.bat
现在想把C:\WINDOWS\system32\test.bat提出来,该如何写代码?

[ Last edited by namejm on 2006-5-27 at 10:58 ]
作者: namejm     时间: 2006-5-28 14:28    标题: xcopy复制了0个文件也算执行成功吗?

发现了一个问题:
当没有更新备份的时候,即xcopy执行后提示"复制了0个文件"的时候,按照我的本意,是不用在log.txt文件里写入任何内容的,结果却写入了内容,难道xcopy复制了0个文件的时候也算执行成功吗?如果也算的话,&&及其之后的内容该怎么写?

[ Last edited by namejm on 2006-5-28 at 17:17 ]
作者: willsort     时间: 2006-5-28 22:05
Re namejm:

      21楼at命令的记录输出,是以换行符(ASCII:0A)而非回车换行符(ASCII:0D 0A)作为行结束,而记录域之间以普通的空格界分。因为记事本工具只能识别回车换行符,所以行被粘接显示,但是在我的测试中,这并不影响for对at命令输出的识别。以下命令是正常执行的。

     for /f "skip=2 delims=\ tokens=4" %%f in ('at') do ...

     22楼的第4条记录显示,是因为三个执行日(星期一 星期二 星期三)无法同时显示,所以用省略号替代显示,不影响任务的属性。如果你想抽取任务的执行日,则需要其它的方法。

     23楼的差异比较,那要看文件属何种差异类型,是文件2.txt总大于1.txt,还是1/2互有不同内容,相同记录是否在同一行等?这决定了代码的复杂度。

     24楼xcopy的返回值确实是这样的规则,因为它找到了源文件,并且复制过程中没有出现错误或被用户中止。暂时解决的办法是用find/findstr过滤xcopy输出结果。

     xcopy /d /h /i /k /f /s /y "%source%"  "%destination%" | find "->">nul && (...
作者: namejm     时间: 2006-5-29 23:24


  Quote:
Originally posted by willsort at 2006-5-28 22:05:
Re namejm:

  23楼的差异比较,那要看文件属何种差异类型,是文件2.txt总大于1.txt,还是1/2互有不同内容,相同记录是否在同一行等?这决定了代码的复杂度。

2.txt总是大于1.txt
我的本意是:检测at任务中用到的bat批处理程序,提取"命令行"栏目下的bat文件名,然后和%systemroot%\system32目录下的bat文件作个比较,如果不在at任务栏中,并且是本程序创建的(标志符为Code by JM) ,则删除该bat文件.
该如何处理?
作者: namejm     时间: 2006-6-1 01:46    标题: 怎么找到特定的程序?

想在%systemroot%\system32目录下所有的bat文件中,找到由特定程序创建的bat批处理(标志符为Code by JM),执行以下程序,结果把所有的bat批处理都显示出来了,不知道是为什么.
@echo off
:: 为什么不是特定程序创建的也在结果中显示呢?
for /f %%i in ('dir /a /b %systemroot%\system32\*.bat') do (find /i "Code by JM" %systemroot%\system32\*.bat>nul 2>nul && echo %%i由特定程序创建)
pause

作者: willsort     时间: 2006-6-1 17:08
Re namejm:

    27楼的代码问题出在find中(红色粗体部分为修改后的结果)。

  Quote:
@echo off
:: 为什么不是特定程序创建的也在结果中显示呢?
for /f %%i in ('dir /a /b %systemroot%\system32\*.bat') do (find /i "Code by JM" %%i >nul 2>nul && echo %%i由特定程序创建)
pause

分析26楼的需求,不用比较文件也可以实现,以上述代码为基础,做以下修改;代码未做任何测试,请谨慎使用!
for %%i in ("%systemroot%\system32\*.bat") do (
    at | find /i " %%i" >nul 2>nul || find "Code by JM" "%%i" >nul 2>nul && echo del /f %%i
)
[ Last edited by willsort on 2006-6-1 at 17:11 ]
作者: zhouhb     时间: 2006-6-1 17:20
版主真是好人啊!谢谢你!
作者: namejm     时间: 2006-6-1 19:51


  Quote:
Originally posted by willsort at 2006-6-1 17:08:
Re namejm:

    27楼的代码问题出在find中(红色粗体部分为修改后的结果)。


  Quote:
@echo off
:: 为什么不是特定程序创建的也在结果中显示呢?
for /f %%i in ('dir /a /b %systemroot%\system32\*.bat') do (find /i "Code by JM" %%i >nul 2>nul && echo %%i由特定程序创建)
pause



分析26楼的需求,不用比较文件也可以实现,以上述代码为基础,做以下修改;代码未做任何测试,请谨慎使用!
CODE:  [Copy to clipboard]
--------------------------------------------------------------------------------

for %%i in ("%systemroot%\system32\*.bat") do (
    at | find /i " %%i" >nul 2>nul || find "Code by JM" "%%i" >nul 2>nul && echo del /f %%i
)

两段代码均无法达到目标,第一段如果去掉>nul 2>nul 后会显示"找不到文件-×××"
第二段干脆无任何显示.不知道是为什么.
作者: namejm     时间: 2006-6-1 20:45
又试了几次,发现第一段代码for /f %%i in ('dir /a /b %systemroot%\system32\*.bat') do (find /i "Code by JM" %%i >nul 2>nul && echo %%i由特定程序创建)不能执行的原因是%%i只是文件名,应该带上完整的路径,改%%i为%systemroot%\system32\%%i后达到预期目标.
      而第二段代码是能够达到预期目标的,只是在试的时候,特定程序都在at计划任务中,后来手动建立了一个内容只有code by jm的test.bat文件测试,完全通过,看来是自己的测试的时候,丢三落四的,遗漏了一些条件,做了很多无用功.
      感谢版主对本帖的持续关注,使得我的脚本中很多功能得到及时的完善.
      这个备份脚本已经涵盖了文件路径检查、开机自动更新、定时更新、日志更新、剩余空间检查、备份任务卸载……做得比较完善,打算今天更改完之后,将不再对这个脚本作更新.
作者: willsort     时间: 2006-6-1 22:28
Re namejm:

      OK!既然兄打算出六一终结版,为表示支持,再提供两点建议。

      注意到:change_character段仅在:subarea_noexist段中被调用了一次,而盘符%subarea2%也只是简单的回显了一次,似乎没有UpperCase的必要;如果有其他理由,那么推荐另外一种更简洁的方案[1]。

      另外,将脚本中的注释内容按照78的行宽重新排版了一次[2]。
[1]UpperCase
echo Wscript.Echo UCase("%subarea2%")>~Upper.vbs
for /f "tokens=*" %%a in ('cscript //nologo ~Upper.vbs') do set subarea2=%%a
for %%f in (~Upper.vbs*) do del %%f
[2]Remark

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::    文件备份器V1.7(for WinXP only)      Code by JM  2006-5-31 QQ:13132002
::
::  功能:1、自由指定要备份的目录(或文件)、位置、备份时间和任务名称
::        2、能检测输入是否正确
::        3、能生成备份日志
::        4、能多次添加备份任务
::        5、能批量停止指定的备份任务
::  原理:只有当源文件修改时间比目标文件的修改时间新时才更新文件;受系统限制,
::        时间只能精确到小时;
::
::  更新历史:
::
::  06.5.31   
::          在注册表中( 位置是:HKEY_CURRENT_USER\Software\Microsoft\Windows\
::      CurrentVersion\Run) 增添了开机自动运行备份程序的键值( 以备份任务名称作
::      为键值) ,尽可能减少错过备份的情况;如果更新了内容,则备份完毕后自动打
::      开备份日志;修正了几处错误;此为V1.7;
::  06.5.30   
::          完善了备份流程,在列出创建备份任务的清单时,可更改备份任务内容;在
::      创建备份任务的同时,强制启动计划任务服务,并立即作复制操作;显示各磁盘
::      分区剩余空间情况的时候,增加了显示磁盘卷标名的功能;更改了注意事项界面
::      中的前景色和背景色,使色调显得明快而柔和;
::  06.5.28   
::          增加了在每周的指定日期进行备份的功能;添加了当计划任务出错时提交报
::      告的功能;完善了日志记录功能,只有当文件更新时才会改写日志;完善了注意
::      事项中的内容;增加了删除所有计划任务的功能;此为 V1.6 ;
::  06.5.26   
::          增加了不允许把保存路径设置为与源文件路径相同、或者为源文件某一目录
::      的功能;添加了注意事项提示功能;修正了几处错误;部分代码参照中国DOS 联
::      盟论坛(http://www.cn-dos.net/forum) 网友bagpipe 所发帖子,使一些代码得
::      到精简;此为V1.5;
::  06.5.25   
::          增加了把备份文件的保存目录拖曳到窗口执行的功能;增加了批量停止指定
::      备份任务的功能;修改了几处错误;精简了部分代码;此为V1.4;
::  06.5.24   
::          增加了把要备份的文件拖曳到窗口执行的功能;感谢中国DOS 联盟论坛
::      (http://www.cn-dos.net/forum)版主willsort提供代码;此为V1.3;
::  06.5.23   
::          修正了一处关键错误,使得备份能顺利进行下去;在中国DOS 联盟论坛
::      (http://www.cn-dos.net/forum)版主willsort等网友的热心帮助下,增强了程
::      序输入错误检测能力,并修正了一些拼写错误,在此深表谢意;
::  06.5.22   
::          修改了显示各分区剩余空间的代码,使显示界面的框线自动适应剩余空间条
::      目下不同长度的字符;
::  06.5.21   
::          增添了停止指定备份任务的功能,使本程序的功能进一步完善;增添了将备
::      份后的文件设置为" 系统+ 只读" 属性的功能,从而在一定程度上提高了备份后
::      的文件的安全;修正了几处错误;优化了部分代码;此为V1.2;
::  06.5.20   
::          头两天的算法存在备份不完全的弊端,今天把copy命令更改为xcopy 命令,
::      从而使本程序能够备份指定目录下除空目录之外的所有文件( 包括目录之下还有
::      子目录、子目录内含有文件的文件嵌套) ,并使代码得到了精简;头两天的代码
::      生成备份任务批处理的时候,因为自动命名的程序名称是固定的,如果有不同的
::      备份任务的话,最后一次任务将把上一次的任务删除,今天把备份任务的命名改
::      为手动指定;增添了多次添加备份任务的功能;此为V1.1;
::  06.5.19   
::          增加了系统检测功能,使得该程序只能运行于XP操作系统下;编写输入错误
::      检测代码,使输入错误能得到及时更改;统一了交互界面,看上去更加美观;本
::      来想增加指定每周的某几天进行备份操作的功能,但是一直未能实现,只好暂时
::      放弃,留待下几个版本解决;优化了部分冗余代码;
::  06.5.18   
::          在对本人电脑上重要资料进行备份的时候,深感手工备份的烦琐,而网上的
::      备份软件又有诸多限制,正好本人在自学DOS 批处理编程,于是花了半天的时间
::      来构思本程序的核心功能,编写初步代码;此为V1.0;
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::


[ Last edited by willsort on 2006-6-1 at 22:30 ]
作者: willsort     时间: 2006-6-1 23:35
Re namejm:

      对1.7版进行了简单的测试,遇到以下问题:

      首先,在生成备份任务时,有错误信息输出,经查证,是因为:build_batch段中有三行代码被折行,其中的输出的文件名部分被截断。经修复后,原问题消失。

      其次,在输入备份日期时,无法只在每月1日备份,因为1分配给了返回到上一部的功能。另外,也存在着不同界面下功能键的设定功能不统一的问题,比如1和0,而他们有可能作为日期、任务ID或者其他正常内容的输入,所以建议换用其它的键。

      再次,在注册表Run项中添加备份任务似存在问题,备份任务的批处理没有时间控制语句,有可能会导致每次启动时执行一次备份,而这未必是用户所希望的。同时,在卸载某个任务后,相关的启动项并没有被清除。如果想避免错误备份时间,就需要在每次启动时,对任务要求进行判断,这显然增大了任务批处理的复杂程度,所以建议将时间判断和备份任务模块写入到主批处理中,而只在任务批处理中调用相应的模块。

      另外,在备份文件夹时,并未将文件夹本身备份,这可能是用户所希望的,也可能是所不希望的,但是习惯上的做法是保持备份目标的结构完整,而文件夹本身显然也是结构的一部分,这需要在xcopy语句上作一些调整。

      最后,考虑到system32中有许多重要文件,一旦程序运行出现差错,很可能对系统造成较大影响,从其中找到批处理进行调试也很困难,建议%batch_directory%从临时目录%temp%,当前路径.,程序所在路径%~dp0和%APPDATA%\%~n0 等路径中选择其一。如果却需要在默认搜索路径,或可放在%systemroot%下。
作者: namejm     时间: 2006-6-2 00:05
关于盘符小写转换为大写一节,主要是为了显示的美观,同时也作为一个技巧放在脚本里.我写这个脚本的时候,尽量避免产生临时文件.考虑到为了美观而罗列了20多行代码,显然有点臃肿,在下个版本中将去除该节.
感谢版主的排版,因为没4:3的显示器,那就采用版主78行宽的格式吧.
正打算出终结版本呢,结果又测试了几种情况,发现对路径输入的检查还有难以解决的问题,看来得等我把儿童节过完之后才能出终结版本:)
具体问题是:
在下面的代码中,当路径带前后双引号且带空格时,将直接退出程序,达不到预期的目的,原因是当"%source%"会将此路径从空格处分成两节,造成语法错误,而如果将判断是否输入空白的语句放到去除路径前后引号的语句之后,则当输入为空时同样会直接退出程序.呵呵,好象又是一个两难的选择.
set source=
set /p source=           请输入要备份文件的路径:
if "%source%"=="" goto input_source
set source=%source:"=%
输入保存路径一段也存在同样的问题.
不知道该如何解决.

[ Last edited by namejm on 2006-6-2 at 00:29 ]
作者: namejm     时间: 2006-6-2 01:05
嘿嘿,老大一出马,就挑出了很多疏漏之处,感激不尽.
你说":build_batch段中有三行代码被折行",在我的电脑上检查不出来,难道这又是宽屏惹的祸?
功能键不统一确实是个问题,正在头痛,在未能统一之前,将就用一下吧:)只是把1作为返回上一步而导致不能在每月的1号备份,当时确实没注意到,马上就改.
在注册表Run下添加键值,得做个选择界面,用户可以放弃开机自启动的功能,然后在停止某项备份任务的时候,自动检测备份任务程序是否还在at中运行,如果不再运行的话,则删除system32下的备份任务程序和注册表Run下相应的键值,这部分的代码6.1的时候才写出来,这也是我这两天接连发帖求助的原因.占用了不少版面,离灌水已经很近了:)打算把34楼及版主提到的几个问题一并解决,做成V1.8再放出来.估计做到V1.8版本就已经功德圆满了:)因此V1.7暂时不作更新.
xcopy命令复制A文件夹时,要加什么参数才能在新的目录下重建A文件夹并保持其下的文件结构,我现在还不得而知,不知道版主能不能提供.要不然,就只能在保存文件的界面中输入路径的时候,提示用户建立一个与A文件夹同名的路径了.
关于%batch_directory%保存路径问题,当初只考虑到保存位置的隐蔽性(很少有人去动%systemroot%\system32下的程序),以免被错误删除导致备份错误,没考虑到系统的安全性问题,看来%APPDATA%\%~n0 是个不错的选择.
另外,这个帖好象就只几个版主在关注,而版主们事务繁杂,没什么时间测试,导致自己的脚本什么地方出了错都浑然不觉.这个脚本自己一个人陆续弄了半个月,没有大家的反馈,一是找不到什么错误,二是无数次的测试也挺累的,三是没有了当初的激情,再做下去就没什么意思了.可能到时候会弄个final版,然后编译成.exe格式,传到坛子上之后就溜之大吉了.呵呵,牢骚话.

[ Last edited by namejm on 2006-6-2 at 01:13 ]
作者: willsort     时间: 2006-6-2 01:30
Re namejm:

      兄大概注意到了,在主题列表中本主题的标题被红色下划线高亮,这表明它有成为[精华]和[置顶]主题的潜质,所欠缺的只是进一步完善,所以希望兄能继续努力。

      引号问题在[1]中已经讨论过了,对于你遇到的情形,可以考虑使用其中2-7的方案[2]。

      折行代码在顶楼帖中可以观察出来,有三处在>>"%之后出现一个空行。

      xcopy带目录名的用法,可以参考(未经测试)
         for %%p in ("%source%") do set destination=%destination%\%%~nxp
         xcopy /d /e /g /h /i /q /x /y "%source%" "%destination%"
      
[1] [讨论]如何从用户传入的参数中去掉引号?
http://www.cn-dos.net/forum/viewthread.php?tid=20838

[2] Get variable witout quotes
set source=
set /p source=           请输入要备份文件的路径:
set "source=%source:"=%"

作者: namejm     时间: 2006-6-2 03:21
下面这段代码在输入为空的时候仍然会出错.天色已很晚了,眼皮在打架,早上起来再好好看一下去除引号的文章,希望能完美地解决我的问题.
set source=
set /p source=           请输入要备份文件的路径:
set "source=%source:"=%"
再次感谢willsort.
作者: willsort     时间: 2006-6-2 12:20
Re namejm:

      确未注意到变量为空的情形,不过,对于本程序来说,可以使用附录的代码。

      另外,插入空格的排版效果不佳,是因为页面中缺省字体的空格宽度只有汉字的1/3,需要使用6个空格,才能空出两个汉字的缩进。但是,在帖首和[/code ]、[/quote] 等代码后的空格会被剔除,因此我在发帖时帖首会使用To/Re字样,所有的引用和代码尽量转移到帖尾。

      另外的解决的方法是,使用两个全角空格,这样不论页面使用何种字体,在任何位置都会保持两个汉字的缩进。只是为了输入半角的英文,需要进行频繁的Shift+空格切换。
set source=:
set /p source=           请输入要备份文件的路径:
set "source=%source:"=%"
:: 上面这句为判断%source%中是否存在引号,有则剔除。
if "%source%"==":" goto input_source
[ Last edited by willsort on 2006-6-2 at 12:24 ]
作者: namejm     时间: 2006-6-2 12:50
re willsort:

  原来是全角和半角的差异,回个帖子测试一下:P
  在下面的代码中,以前也想过应该在%source%字符串前加个特殊符号来标注一下,然后在if语句中测试这个特殊符号与输入是否完全匹配来解决,但是一直没想到要在set source=这句上作改动,导致尝试以失败告终。
  刚回来就看到了版主的代码,好激动。终于把一个关键问题给解决掉了!
  
set source=:
set /p source=           请输入要备份文件的路径:
set "source=%source:"=%"
:: 上面这句为判断%source%中是否存在引号,有则剔除。
if "%source%"==":" goto input_source
[ Last edited by namejm on 2006-6-2 at 12:54 ]
作者: namejm     时间: 2006-6-2 13:46
Rn willsort:
  
  以下代码复制文件夹的时候,确实能保持原有文件夹的文件结构,但是,如果要复制的是文件而非文件夹的时候,就会建立一个以"文件名.后缀名"为名字的文件夹,该文件夹下将只有孤零零的一个文件,反倒加深了文件的层数。
  解决此问题的初步设想:
  在保存路径的时候,提示用户作如此选择:如果要备份的是文件夹时,要求输入与文件夹名相同的路径;如果是单个的文件而非文件夹时,直接输入任意路径。
  但是这样做的话,无形中会加大手动输入路径的工作量。
xcopy带目录名的用法,可以参考(未经测试)
         for %%p in ("%source%") do set destination=%destination%\%%~nxp
         xcopy /d /e /g /h /i /q /x /y "%source%" "%destination%"
[ Last edited by namejm on 2006-6-2 at 13:51 ]
作者: willsort     时间: 2006-6-3 20:42
Re namejm:

      把文件和文件夹的判断转交给用户,的确不是一个好的选择,我们可以自行判断。

for /d %%p in ("%source%.*") do set destination=%destination%\%%~nxp
xcopy /d /e /g /h /i /q /x /y "%source%" "%destination%"
作者: namejm     时间: 2006-6-4 00:09
Rn willsort:
  
  看到老大经常用for语句,往往一两句就能使很复杂的问题迎刃而解,万分PF,同时也感到for语句的强大,真该好好揣摩一下for的用法了。
  对比了一下老大写的xcopy语句xcopy /d /e /g /h /i /q /x /y "%source%" "%destination%"和我自己写的xcopy /d /h /i /q /s /y "%source%" "%destination%",有好几个参数不太一样,老大的比我多了/e /g /x,舍弃了/s,把文件的审核设置、空文件夹等都继承过来了,称得上是真正的备份,看来自己考虑不周,得该一下参数了。
  不过,个人觉得复制空目录意义不大,不知道老大是基于什么原因要舍弃/s而用/e。
作者: willsort     时间: 2006-6-6 17:55
Re namejm:

      使用/e的目的仍然在于尽可能地保持备份结构的完整,无论如何,这是所有备份程序的责任。同时,一个目录是否为空目录,并不能作为它是否具有备份价值的依据,在很多情况下,空目录可以起到标识性的作用,所以备份它是有用的。

      目前,正在考虑是否启用cmd自动完成功能来辅助et /p的路径输入,因为自动完成缺省是关闭的,而打开的方法需要使用cmd /f:on,这会创建一个新的CMD实例,可能会带来一些附加的影响,你可以先行使用一下。
作者: namejm     时间: 2006-6-6 21:48
Re willsort:
  关于启用文件和目录名的自动完成功能,书上是这样说的:
  “通过设置下述REG-DWORD值,可以在计算机上或用户会话中启用或禁用所有cmd命令处理的文件和目录名完成:
  HKEY_LOCAL_MACHINE\Software\Microsoft\Command Processor\CompletionChar\REG_DWORD
  HKEY_LOCAL_MACHINE\Software\Microsoft\Command Processor\PathCompletionChar\REG_DWORD
  HKEY_CURRENT_USER\Software\Microsoft\Command Processor\CompletionChar\REG_DWORD
  HKEY_CURRENT_USER\Software\Microsoft\Command Processor\PathCompletionChar\REG_DWORD
  要设置RE_DWORD值,应运行Regedit.exe并使用特定功能的控制字符的十六进制值(例如,用0×9表示TAB键,用0×8表示BACKSPACE键)。用户特定设置优先于计算机设置,并且命令行选项优先于注册表设置
。"
  本人目前还属于注册表菜鸟,并且对用16进制值来表示控制字符一窍不通,对版主提出来的"先行使用一下"的建议也是心有余而力不足,急切盼望版主能给个示例。

[ Last edited by namejm on 2006-6-6 at 23:27 ]
作者: willsort     时间: 2006-6-6 22:31
Re namejm:

      注册表中的已经缺省设置自动完成的的控制键,Ctrl+D为目录完成,Ctrl+F为文件完成。我们可以不用管它,直接使用cmd /f:on 即可,下面是一个简单的示例。
@echo off
if not "%1"=="$" %comspec% /f:on /c %0 $ && goto :eof
::插入其它的代码
echo. Ctrl+D: directory completion; Ctrl+F: file completion
set /p test=Please input path:
echo.%test%
::插入其它的代码

作者: namejm     时间: 2006-6-7 00:18
Re willsort:
  
  在本程序脚本的最开始加入版主提供的代码if not "%1"=="$" %comspec% /f:on /c %0 $ && goto :eof,确实能实现自动完成文件名的功能。只是在测试过程中,发现了如下图所示的奇怪现象。
  出现问题的条件是:当按Ctrl+F或者Ctrl+D输入的文件名比上一次短得多的时候,会在文件名后有上一文件名的残余,如果一次比一次更短,则有更多的残余出现,但是并不影响程序的正确执行。
  另外,对这句代码的确切含义并不了解,版主能否解释一下?
附件 1: 错误的显示.jpg (2006-6-7 00:18, 8.2 K, 下载附件所需积分 1点 ,下载次数: 8)



作者: willsort     时间: 2006-6-7 21:31
Re namejm:

      这个现象在我的测试中也出现了,而且在CMD环境中也存在。这也是我所说的“附加的影响”之一,目前我尚未发现好的解决办法,只能推测是cmd自动完成特性存在一些问题。不过它并不是在所有文件名由长变短的时候出现,具体的规律和解决的办法希望其它达人也能想想办法,或者你也可以在命令行区或解答室发表求助主题。

      关于 if not 一句的含义,意为当命令行第一参数不为"$"时使用cmd(%comspec%指向cmd的位置)重新调用批处理自身,调用的同时加上第一参数$以防止cmd的反复调用。因为我们要使用cmd /f:on来开启自动完成的扩展特性,而在批处理中使用cmd会创建新的cmd环境,从而中断批处理运行,所以需要在其后使用/c %0重新进入批处理自身。

      这就是所谓的“批处理重入”技术,这里使用重入技术就是为了获取一个新的符合特定要求的命令行环境来解释一个特殊的批处理程序或者自身[1][2];而另外一些时候,批处理的重入不是通过cmd而是call或者直接调用批处理来实现,这通常是为了实现命令行参数的重新设定[3]。

     另外,已知的附加影响还包括:批处理中的所有环境变量将变成“局部”的,在退出批处理后将失效;系统环境变量%cmdcmdline%将被修改;运行过程中内存中将增加一个新的cmd实例(进程)。

[1] [原创]无奈何签名代码略析
http://www.cn-dos.net/forum/viewthread.php?tid=18838

[2] 关于 HDKP 的几点技术探讨
http://www.cn-dos.net/forum/viewthread.php?tid=12892#pid95281

[3] 已结:将文件名改为001.txt 010.txt...100.txt
http://www.cn-dos.net/forum/viewthread.php?tid=14512

[ Last edited by willsort on 2006-6-7 at 21:32 ]
作者: willsort     时间: 2006-6-8 01:31
Re namejm:

      刚才经过简单的测试,可以确定自动完成仅在完成中文名(或其它多字节字符名)文件或目录再次完成时出现问题。已将讨论帖转发在命令行区[1]。

      但估计此问题短时间内无法解决,再鉴于其不影响正常使用,可以考虑暂不作处理,当然用与不用还需要你自己来做权衡。另外,set /p 与cmd的命令提示符类似,可以使用DOSKey的一系列特性,使用光标键翻阅历史命令,而这些命令当然包括曾经输入的文件名,也可以使用ESC、F1至F10这些功能键辅助输入。另外,也可以使用右键菜单中的复制粘贴功能。

      除此而外,我尚在考虑,是否可以将这个程序由定时备份改为定期备份,以避免备份时间经常被错过的问题,当然这需要大幅修改代码,也需要你做一下权衡。


[1][讨论]CMD自动完成特性对中文文件和目录名存在问题
http://www.cn-dos.net/forum/viewthread.php?tid=21091
作者: namejm     时间: 2006-6-8 19:27
Re willsort:

  后来想了一下,文件名的自动完成功能是一个比较高级的技巧,如果不是版主提出来,估计很多人都没想到。而在这个脚本程序中,已经有了用拖曳的方法来选择文件,很是省事,并且在运行的时候不会产生什么意外;而用文件名的自动完成功能,需要用组合键来多次选择才能找到要备份的文件,这个操作就显得比较烦琐了,何况会带来一些麻烦。基于以上情况,我觉得文件名的自动完成功能似乎可以取消。个人意见,欢迎探讨。
  在我的机子上(xp+sp2),我一直在使用doskey的光标键翻阅历史命令的功能,不知道是不是系统默认开通的,所以在我的脚本程序中没有作这方面的提示。粘贴的方法,则没有作提示,在下版中将改进,以方便操作;而ESC、F1~F10这些功能键也没作提示,则是因为自己觉得在输入的时候可能不会有这么烦琐的输入,没有必要作任何提示。
  不知道版主定期备份的具体操作是什么,定时备份不就已经含有定期备份的功能了么?请版主明示。
  最近在忙单位的事情,6.10之后才会有比较多的时间来考虑这个脚本的更新,请各位原谅。
作者: willsort     时间: 2006-6-9 02:30
Re namejm:

      定期备份与定时备份的算法区别主要在于它将不再依赖“计划任务”,或者说不再主要依赖“计划任务”。

      定期备份算法主要描述如下:

      首先,将自身代码或相应的任务代码与系统的启动时自动运行机制挂钩,确保在每次系统启动时可以运行;然后,在运行时判断当前日期是否符合用户预先设定的条件,如果匹配则启动指定任务,否则不做任何动作。

      算法的核心在于自动运行挂钩和日期条件判断,在这两方面我只有比较初步的想法,还有一些细节需要完善。

      算法的优势在于,因为它可以采用任务有效期机制,所以可以大幅避免“计划任务”因系统未启动而被跳过的可能性,这对不能保持不间断开机运行的个人用户比较有利。
作者: namejm     时间: 2006-6-9 07:46


  Quote:
Originally posted by willsort at 2006-6-9 02:30:
Re namejm:

      算法的优势在于,因为它可以采用任务有效期机制,所以可以大幅避免“计划任务”因系统未启动而被跳过的可能性,这对不能保持不间断开机运行的个人用户比较有利。

 
  我已经在脚本中加入了强制启动计划任务的代码,应该可以保证用得上计划任务吧?不知道在比较BT的设置中是否有效,还需要大家多作测试。

  就算计划任务启动失败,但是已经加入了开机自动运行的代码,每次开机的时候还是能够运行备份脚本,可一定程度上弥补计划任务启动失败的不足。

  目前觉得这是个双重保险的做法,老大可能还有更完善的方案,能不能透漏一下呢?
作者: willsort     时间: 2006-6-9 18:33
Re namejm:

      例如,设定备份任务A在从1日开始每7天运行一次,但在1日这一天,用户从未启动系统,任务显然无法被执行;然后,假设用户在2日启动系统,此时是否需要执行任务A呢?作为备份任务来说,一般是需要的;再后,用户在3日再次启动系统,此时是否需要再次执行任务A呢?通常是不需要的。

      这只是通常的情况,我们可能还需要照顾用户更复杂的需求。比如用户可以设定,任务过期1~2天则自动执行,过期3~4天则询问是否执行,过期5~6天则不再执行;而在过期的任务执行后,下一次任务执行时间是按新的周期是重新调整,还是保持原来的计时周期?

       这些用计划任务将难以实现,除此而外,计划任务还有更多的缺陷,比如无法设定任务自系统启动时运行,无法设定任务在系统总运行时间达到一定时限时运行,甚至无法设定任务每4天或者每5天执行一次(并非每月的固定几天)。所以,我个人从不使用“计划任务”。

      简而化之,定时定的是“时钟”,定期则定的是“期限”。至于何者更符合设计者的定位和使用者的需求,则是另外一个更复杂的问题了。
作者: namejm     时间: 2006-6-9 19:39
  对于每隔N天运行一次或者每次开机时运行一次的需求,可以改用XP及其之后的系统中的schtasks命令来实现。
  看了此命令的介绍,感觉很是强大,但是功能强大的背后,是可选参数太多的弊端。如果把这个命令用于交互界面,必将使用户不停地作出选择,过多的干涉会增加用户的工作量,而我想使这个脚本尽可能地减少用户的操作,所以必然会舍弃一些功能。
  当然,DOS不是万能的,我也没指望这个脚本能取代目前用各种高级语言编出来的备份程序,只是边学边用,看看批处理到底能替我节省多少重复劳动,给我带来哪些方面的方便等等。尽可能多地榨取批处理的血汗,则是我所孜孜以求的
  BTW,我相信这个脚本还有其他可供开发的功能,只是我目前还没想到而已,正在学习之中。感谢版主一直以来的指引,也希望你能继续关注下去。Thanks。
作者: willsort     时间: 2006-6-10 18:47
Re namejm:

      粗略翻阅了schtasks,它应该是XP下计划任务的全功能命令行接口,确实比at增强了不少。多谢兄的提示!

      至于参数太多的问题,因为对备份任务来说很多参数可以取缺省值,真正要选择的项目不是很多,所以可以用代码简单的封装一下。

      如果说,还有什么可以增强的地方,那就是备份的模式与命令行接口了。

      目前,程序所采用的备份模式是差异备份,当然还存在其它的一些的备份模式,比如同步备份、增量备份等,这些模式用批处理也应该是可以实现的。

       至于命令行接口则主要是为了简化任务脚本的设计,如果增加了更多的备份模式,则将备份代码写入任务脚本中则过于冗繁,而如果将代码写入宿主脚本中,在任务脚本中仅写入调用的接口,则任务脚本会简单得多;进而可以考虑直接将备份任务以命令行的形式写入到计划任务的命令行中,从而省略任务脚本的设计。

[ Last edited by willsort on 2006-6-10 at 18:48 ]
作者: namejm     时间: 2006-6-11 00:10
Re willsort:
  
  "进而可以考虑直接将备份任务以命令行的形式写入到计划任务的命令行中,从而省略任务脚本的设计。"
  ——我觉得如果这样做的话,那就脱离了我设计这个脚本的初衷:让用户不用记命令格式,只管按照提示做简单的输入操作就能完成备份。

  另外,对于增量备份和同步备份,我不知道具体的概念是什么;还有,“宿主脚本”是什么意思?我是菜鸟,属于对比较专业一点的术语一看就晕菜的那种,别笑话我
作者: willsort     时间: 2006-6-12 18:53
Re namejm:

      关于备份模式请参考[1]。

      命令行接口是供备份任务所使用的,而非用户自己。也就是说,用户依据向导创建的备份任务,原来包括一个计划任务和一个对应的任务脚本,而这个脚本相对于文件备份器相对独立的。现在,我们可以让这个任务脚本,直接调用文件备份器中相应的备份模块。此时,因为任务脚本是由文件备份器生成的,而且其功能也是由文件备份器支持的,所以我称现在的文件备份器为“宿主脚本”。

      极端简化的任务脚本将有只有一个命令行,而诸如检测、判断、备份、日志等任务全部交由宿主脚本来完成,而这个命令行是可以写到计划任务或者Run的键值中去的。而此时,任务脚本将不再存在。

[1]为了恢复的备份
http://www2.ccw.com.cn/05/0528/b/0528b16_1.asp
作者: namejm     时间: 2006-6-12 23:04
  看了"为了恢复的备份"一文,觉得还是差异备份好一点,因为我给这个脚本的定位是:只要满足个人用户备份重要的小文件就可以了,基本不考虑上百兆文件的备份。至于更复杂的备份模式,如果哪位有兴趣,可以自行开发,不一定用CMD命令。

  关于“宿主脚本”的想法,我觉得要实现起来还是有点复杂,有点难度:如果要用任务脚本调用文件备份器中的相关模块,则文件备份器的位置和文件名必须固定不变;如果取消任务脚本,将命令写入at命令行或者注册表run中,则备份器中相关模块的变量该如何赋值才能得知要备份的是哪个文件,将要备份到什么地方去?
作者: namejm     时间: 2006-6-15 18:05
  增加了对日期和时间输入的错误检测,还不够完善,请各位高手指正。

  感谢bagpipe提供代码。
作者: namejm     时间: 2006-6-29 13:50
  增加了一个比较实用的功能:从备份后的文件中恢复文件到原始目录处。

  这个功能居然耗费了我几乎整整一天的时间,难点在于要把每个文件及文件夹及其对应的属性记录下来,然后再用attrib命令进行操作。一开始,我就要求自己不产生临时文件,结果无功而返,迫不得已,只好放宽要求,临时文件从3个减少到1个,终于把这个模块做出来了。

  在做这个模块的时候,有了一些收获:比如,用for /r 遍历目录的时候,并不能用%~ai探测到隐藏文件的属性,但是在in后的括号中用dir /a /s /d之后,就可以完美地解决。

  还是希望能不产生临时文件,希望能有高手来关注。
作者: willsort     时间: 2006-6-29 22:21
Re namejm:

      目前,尚未观察到属性操作的必要性。xcopy可以选择复制属性,开关是/K,与此有关的开关还有/R和/H。
作者: namejm     时间: 2006-6-29 22:59
  因为在备份的时候,为了防止对备份后文件进行改动,备份后的所有文件都已经设置成"系统+只读"属性,如果在恢复文件的时候,不恢复这些文件的原始属性,会导致一些意想不到的问题:比如说不能再对恢复后的文件进行诸如改名、更新内容等操作。这也是我在恢复文件的时候才发现的问题,所以增加了对属性的操作。

  当然,在备份的时候,是可以用参数/k来保持原始的属性,但是这样做了之后,就不能防止对备份后的文件进行改动。为了备份文件的保险起见,还是弄复杂点的好:)
作者: namejm     时间: 2006-7-1 01:21
  在回其他帖子的时候,再次查看了这个脚本中对日期的检测这段代码,发现如果要对星期式日期的输入作检测,其原理和对数字式日期的检测其实是一样的,只不过要用到findstr命令中的某个技巧而已,于是马上挑灯夜战,完善了对日期的检测。
作者: namejm     时间: 2006-7-3 00:26
  从备份文件中恢复文件的功能还有问题,主要是对文件的取名问题,请暂时不要使用该功能。如果要使用,请在生成后的*_revert.bat文件中手动修改文件名,以免恢复出错。
作者: namejm     时间: 2006-7-25 23:05
  有谁愿意来把这个脚本再完善一下?主要是恢复备份这一段。
作者: IceCrack     时间: 2006-7-26 09:30
我只能精神的支持你一下.我等尚须努力
作者: namejm     时间: 2006-7-28 22:32
  已经完善了对备份后的文件进行操作的部分,总体来看,这个脚本作为备份之用的基本功能已经具备了,剩下的工作主要就是查找bug、精简代码了。希望大家不要被大量的代码吓倒,都来测试一下吧。
作者: willsort     时间: 2006-7-29 16:16
Re namejm:

      问心而言,我仍然不赞同出于保护备份文件的考虑,而给程序附加过多的属性操作代码。因为与我们付出的代码和性能的高额代价相比,附加了各种属性的备份被人为修改和破坏的概率不会下降很多。这也是我无法考虑对restore模块作出更新和测试的主要理由。

      也许只给目标目录加上属性是个折中的办法,效果与给所有目标加属性的方法相近,代价则要小得多。

      当然,如果你坚持原来的看法,那么我提出一个对属性操作的:get_attrib段中for语句的改进建议:
for %%a in (a s h r) do echo %%i|findstr "%%a">nul && set a%%a=+%%a || set a%%a=
echo attrib !aa!!ah!!ar!!as!%%j >>"%batch_directory%\%name%_revert.bat"
[ Last edited by willsort on 2006-7-29 at 23:46 ]
作者: namejm     时间: 2006-7-29 22:29
Re willsort:

  当初之所以要给每个目标文件都加上“系统+只读”的属性,是想当用户意外地对其中的某个文件进行删除、重命名等操作的时候,系统会自动提醒是否真的要进行该操作,并没有指望能对付刻意的破坏。如果真要对付刻意的破坏的话,我倒是可以用md test..的方法来建立一个用常规方法无法访问和删除的文件夹来保存备份文件,只是考虑到有可能要对备份后的文件进行访问才放弃了这个刻毒的想法:)

  如果只给最上层的目标文件夹加属性的话,防风险的能力比目前这个方案稍微弱一点,但是建立备份任务的效率得到了提升,有失有得啊。这个版本还是先保留目前的方案,用你精简后的代码替换我原来的那部分,先看看各位的意见再说吧。多谢你一直以来的关注和提供代码。

[ Last edited by namejm on 2006-8-1 at 01:17 ]
作者: willsort     时间: 2006-7-29 23:46
Re namejm:

      发现了67楼代码一个显著和一个不显著的错误,已纠正67楼和顶楼代码。

      第二句的attrib前缺少echo,%%j后应该添加一个空格,否则在%%j为单个数字时出错。
作者: namejm     时间: 2006-7-30 14:40
  呵呵,willsort还真细心,连这么细微的地方都注意到了。在你的提示下,又发现了这段代码之前似乎还应该加上一句setlocal enabledelayedexpansion,以免延迟出错。

  测试了一下目前的代码,发现了两个比较严重的问题,都是和xcopy /d /h /i /g /q /s /x /y "%source%" "%destination%" 这一句中的参数 /s 有关的:
  1、当文件(而非文件夹)位于根目录下时,有时会无法复制成功,提示"不能执行周期性复制";
  2、当要复制的文件之下的目录中存在同名文件的话,会把所有的同名文件复制;

  解决问题1的关键,在于用xcopy的时候,要区分复制的是文件还是文件夹;
  而问题2的解决却有点棘手:如果去掉参数/s,则只能复制指定文件夹的第一层文件,而不能复制文件夹下的所有自文件夹;如果不去掉参数/s的话,这个问题将无法避免。

[ Last edited by namejm on 2006-7-30 at 23:07 ]
作者: chainliq     时间: 2006-7-31 23:23    标题:

敢问版主能不能把修改好的整个程序发出来给我们大家共亨好吗?
作者: chainliq     时间: 2006-7-31 23:55
版主可以把整个修改好的程序放出来让大家代亨吗?
作者: namejm     时间: 2006-8-1 01:20
  花了点时间,把70楼的两个问题解决了;再次测试的时候,发现willsort版主在67楼的 for %%a in (a s h r) 一句中"a"属性似乎有点多余,因为在测试中发现,任何一个文件都有"a"属性,可以不用考虑再用attrib来添加,此举可以在恢复备份后文件的批处理中节省大量的属性操作代码;顺带发现了几个错误,也一并修改。

Re chainliq:

  从现在开始,将在顶楼提供bat和exe两种格式的文件下载,里面有简单的说明,多谢你的关注。

[ Last edited by namejm on 2006-8-1 at 01:38 ]
作者: namejm     时间: 2006-9-15 05:40
  期待大家的测试。有什么问题请跟帖,需要大家共同参与。
作者: vkill     时间: 2006-9-15 06:13
说实话还没有完整的看过这帖子,汗,回去看看学习学习
作者: hj_18     时间: 2006-9-15 20:22    标题: 很好的程序

我现在单位里的电脑是联想的,带有慧盾保护,C盘上无法保存数据,因此像Mozilla Firefox和Thunderbird的安装,配置文件都不能保存,还有许多程序都是要在C:\Documents and Settings下放东西,又不能移动文件夹的位置,确实很麻烦。我最近是这么来保存和备份的,有一次在还原卡解开的时候,我编辑“我的电脑”属性中的“Path"变量,把winrar的路径放进去,然后写个保存设置的文件:
mkbksd.bat
@rar a -u -as -ep3 -r e:\hj\backup\bk\bkfxsd.rar "C:\Documents and Settings\Administrator\Application Data\Mozilla"
@rar a -u -as -ep3 -r e:\hj\backup\bk\bkbirdsd.rar "C:\Documents and Settings\Administrator\Application Data\Thunderbird"

恢复设置
restore.bat
e:
@cd "e:\hj\backup\bk"
REM 尝试用关机备份文件恢复
@rar x -ep3 -o+ bkfxsd.rar
@rar x -ep3 -o+ bkbirdsd.rar

我想如果不能修改Path的内容,也可以在脚本中把rar打上绝对路径,简单用用还是可以的,当然不能和楼主的大作相提并论,只是我想说原来我也有写个这样的脚本的计划,现在就省力开心多了。
作者: htysm     时间: 2006-9-15 22:08
这要花费多大的精力啊。
作者: htysm     时间: 2006-9-15 22:46    标题: 程序有待改善。

这个程序不完善呀,我刚才测试了一下,添加了一个备份作业,然后又删除了这项备份,可程序生成的备份文件并没有删除,并且自启动项里的启动项目也没有删除。:o
作者: namejm     时间: 2006-9-15 23:05


  Quote:
Originally posted by htysm at 2006-9-15 22:46:
这个程序不完善呀,我刚才测试了一下,添加了一个备份作业,然后又删除了这项备份,可程序生成的备份文件并没有删除,并且自启动项里的启动项目也没有删除。:o

  请问你是用这个程序自带的删除功能来删除的吗?如果用自带的来删除,应该删得了启动项目里的启动项的呀,我都测试了好久的。如果确实不能删除,请把你的操作详细地叙述一遍,看是哪个地方出了问题。

  你说程序生成的备份文件没有删除,是指放在%programfiles%下的bat文件没有删除,还是指备份成功后copy过去的文件没有被删除?如果是后一种的话,那正是备份任务所需要的呀:就算程序删除了,但是文件还是保留下来了。如果是前者,还有请你把操作详细地描述一下。
作者: hj_18     时间: 2006-9-16 01:03
我建议试试unxutils,等会儿再聊。
作者: hj_18     时间: 2006-9-16 03:08
其实DOS下的批处理命令是很简陋的,很多时候要做出我们心目中想要的效果比较难,这时候不妨使用一些移植到windows下的Unix工具,很可能事半功倍。

http://unxutils.sourceforge.net/
比如把路径名与文件名分开可以用dirname等等,在我写脚本时发现很有用,以下是我的一个在右键菜单中加入 tar & gzip 压缩的脚本,一个草稿。水平很低,拿出来给大家笑笑。
set tmpdir=e:\temp\
set progdir="D:\Program Files\UnxUtils\usr\local\wbin\"
%progdir%echo -n -E %1 >%tmpdir%1.txt
%progdir%dirname %1 >%tmpdir%2.txt
%progdir%gawk "{print length($0)+2}" %tmpdir%2.txt > %tmpdir%3.txt
for /F %%i in (%tmpdir%3.txt) do %progdir%gawk "{print substr($0,\"%%i\")}" %tmpdir%1.txt > %tmpdir%4.txt
for /F "delims=?" %%j in (%tmpdir%4.txt) do set bsname=%%j
%progdir%gawk "BEGIN{FS=\".\"}$0 ~/\..?.?.?$/{NF=NF-1;print $0}" %tmpdir%4.txt >%tmpdir%5.txt
%progdir%test -s %tmpdir%5.txt
if %ERRORLEVEL%==1 goto noext
for /F "delims=?" %%i in (%tmpdir%5.txt) do %progdir%tar cvf "%%i.tar" "%bsname%" && %progdir%gzip "%%i.tar"
goto end
:noext
for /F "delims=?" %%i in (%tmpdir%4.txt) do %progdir%tar cvf "%%i.tar" "%bsname%" && %progdir%gzip "%%i.tar"
rem del /Q /S %tmpdir%1.txt
rem del /Q /S %tmpdir%2.txt
:end

修改注册表
Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\*\shell\tar压缩]
@="用tar压缩"

[HKEY_CLASSES_ROOT\*\shell\tar压缩\command]
@="D:\\Program Files\\UnxUtils\\bin\\mktgz.bat \"%L\""

[HKEY_CLASSES_ROOT\Folder\shell\tar]
@="用tar压缩"

[HKEY_CLASSES_ROOT\Folder\shell\tar\command]
@="D:\\Program Files\\UnxUtils\\bin\\mktgz.bat \"%L\""
作者: namejm     时间: 2006-9-19 06:19


  Quote:
Originally posted by hj_18 at 2006-9-16 03:08:
比如把路径名与文件名分开可以用dirname等等

  其实,如果只是把路径名与文件名分离开的话,不用第三方软件,CMD中的for语句就可以办到,%%~pi 表示路径名,%%~ni 表示文件名,%%~nxi 表示带扩展名的文件名……呵呵,经过微软的不断改造,CMD已经非常强大了,只是限于我们的认识,还难以发挥它的全部功能而已。看似难以完成的工作,随着你认识的不断深入,就会发现你离成功越来越近,只到最后通过CMD来解决难题,不断有新的发现,不断有新的惊喜,这就是CMD命令行的魅力所在,这也是我们还在对CMD命令行孜孜不倦地探索的动力。呵呵,一点小感慨,扯得有点远了。
作者: hj_18     时间: 2006-9-19 21:03
我只是觉得dos不能把一个命令的输出结果直接赋值给一个变量,还要用个临时文件for一下,有点烦。而且像IF语句什么的不能跟复合语句体,几个语句要在一行上写完,格式上不好看。用FOR从文件中读取东西,怎么都不如gawk什么的方便。我还是试试perl什么的算了。
作者: namejm     时间: 2006-9-20 00:58
  DOS可以把一个命令的输出结果直接赋给一个变量啊,只是一个变量每次只能接收一行的内容而已,完全可以不用临时文件的;如果用到了临时文件,要么就是你的功力还不够,要么就是临时文件有其他用途,要么……要么就是所有的命令行工具都无法绕过去的某种限制。

  if语句还是可以跟复合语句体的啊,你在if set command的set语句和command语句中都可以用一对括号把复合语句体包括进去,可能你用得比较少吧。
作者: caicai     时间: 2006-9-20 08:57
第一次见到那么强大的批处理脚本,支持一下!
作者: hj_18     时间: 2006-9-20 21:08


  Quote:
Originally posted by namejm at 2006-9-20 12:58 AM:
  DOS可以把一个命令的输出结果直接赋给一个变量啊,只是一个变量每次只能接收一行的内容而已,完全可以不用临时文件的;如果用到了临时文� ...

那能不能教教我,举个实例好吗?我实在是搞不明白,谢谢。
啊,看了楼顶的帖子,明白了第二个问题。

今天会了第一个问题。
http://www.cn-dos.net/forum/view ... ge=1&highlight=

[ Last edited by hj_18 on 2006-9-27 at 20:08 ]
作者: TQang     时间: 2006-9-20 23:14
xcopy_parameter参数没用上,是不是有点BUG
作者: uemuem     时间: 2006-10-13 23:12
友情提醒,这里有个小错误:

echo ecoh 不存在,可能已被改名、移动或者删除

这里的ECOH应该是ECHO吧,呵呵

不完善,没法恢复备份文件!

[ Last edited by uemuem on 2006-10-13 at 23:14 ]
作者: namejm     时间: 2006-10-14 00:27
  ecoh确实是echo的笔误,多谢你的提醒,已经修改。

  请问你是在什么情况下恢复不了备份文件的?
作者: uemuem     时间: 2006-10-14 01:57


  Quote:
Originally posted by namejm at 2006-10-14 00:27:
  ecoh确实是echo的笔误,多谢你的提醒,已经修改。

  请问你是在什么情况下恢复不了备份文件的?

前面那个是提示出错,所以我看出来了

在源文件不存在,备份文件存在的情况下,不能把备份文件恢复到源文件的位置,也没有提示出错。。。
具体哪里出问题我也不太清楚,代码我也看不太懂,说实话!:lol:
作者: namejm     时间: 2006-10-19 22:09


  Quote:
Originally posted by uemuem at 2006-10-14 01:57:
在源文件不存在,备份文件存在的情况下,不能把备份文件恢复到源文件的位置,也没有提示出错。。。 ...

  你这个问题我始终没能在我的机子上再现,暂时无法得知问题出在哪里,你最好多测试几次,如果还是不能恢复的话,请把你的每一步操作告诉我。
  不过,倒是在测试的过程中发现,当复制某个子文件出错的时候,这个程序并不能完整地备份文件,至于在什么情况下会复制出错,暂时还不得而知;不过,复制出错的几率是非常低的,大可放心使用。

  Quote:
Originally posted by TQang at 2006-9-20 23:14:
xcopy_parameter参数没用上,是不是有点BUG

  确实属于浪费变量的行为,已经修正,请在顶楼下载测试。
作者: wangjf     时间: 2006-10-21 07:32
无法下载附件
作者: namejm     时间: 2006-10-21 08:50


  Quote:
Originally posted by wangjf at 2006-10-21 07:32:
无法下载附件

  压缩包里包含了bat和exe两种格式,另外还有一个说明文件。测试了一下,发现可以下载,但是下载的文件无法正常打开,也无法正常删除,以前下载其他文件的时候也发现类似的问题,应该是论坛的下载系统出了问题,请换个时间下载,或者直接copy顶楼的代码。
作者: wangjf     时间: 2006-10-21 21:52
已经可以下载了,也可以正常打开.谢谢LZ的及时更新
作者: andred0421     时间: 2006-11-24 15:28
学习中。。。
作者: ihouge     时间: 2007-4-6 13:42
感谢楼主共享!日后一定用得着
作者: namejm     时间: 2007-4-9 00:23
  搁置了将近半年之后,再次更新代码。若没有什么大的bug,将作为final版推出,请有兴趣的测试一下。
作者: yinghao2005     时间: 2007-4-9 04:38
不错
继续努力!
作者: flamey     时间: 2007-4-9 05:26
好东西   顶起来
作者: flyinspace     时间: 2007-4-9 07:53
说句实话,如果不加命令行参数,则这个脚本基本没有用。
作者: vkill     时间: 2007-4-9 08:05


  Quote:
Originally posted by flyinspace at 2007-4-9 07:53:
说句实话,如果不加命令行参数,则这个脚本基本没有用。

大错特错啊~最起码可以学习的啊
作者: flyinspace     时间: 2007-4-9 08:37    标题: 代码初步分析报告。

set /p source=           请输入要备份文件的路径:
set "source=%source:"=%"
:: 上面这句为判断%source%中是否存在引号,有则剔除。
if "%source%"==":" goto input_source
if "%source%"=="0" exit
if "%source%"=="1" goto notice
if "%source%"=="2" goto backup_tasks
if /i "%source%"=="v" goto view_batch
if not exist "%source%" goto source_noexist
for %%i in ("%source%") do if "%%~fi"=="%%~di\" goto forbid_to_backup
:: 判断要备份的是文件还是文件夹,为以后的xcopy操作设置标志
pushd "%source%" 2>nul && (popd & set folder=yes) || (set folder=)

输入为空时,我们采用
if /i "%source%"=="" goto ***

if /i "%source%"=="%*" goto ***
这个来解决。。
这样,当目标不存在的时候。。
可以及时获取错误信息进行修正。。

另外,当被复制文件运行或被占用的时候。

楼主有没有考虑写入日志(给出提示)然后再继续或停止复制呢?

至于非法字符也非常好防御,写一个子程序。
利用 %data:~0,1% 类似的代码就可以搞定。。

楼主,请不要把这个做为最终代码吧:)

还有大量需要更新呢:)

呵呵,吃饭后再分析你的代码。
作者: vkill     时间: 2007-4-9 08:52


  Quote:
Originally posted by flyinspace at 2007-4-9 08:37:
set /p source=           请输入要备份文件的路径:
set "source=%source:"=%"
:: 上面这句为判断%source%中是否存在引号,有则剔除。
if "%source%&qu ...

你说的也不完全正确的啊~我认为这样才是完美解决

http://www.cn-dos.net/forum/view ... ge=1&highlight=

[ Last edited by vkill on 2007-4-9 at 09:36 AM ]
作者: 3391617     时间: 2007-4-9 10:19
VKILL是强          
作者: namejm     时间: 2007-4-9 21:57
  1、

  Quote:
Originally posted by flyinspace at 2007-4-8 18:53:
说句实话,如果不加命令行参数,则这个脚本基本没有用。

  从你的其他回帖可以看出,兄是编程中人,但是却说出这样的话,未免让人感到意外,试问:在面向对象的高级语言中,如果不提供对象的属性让你选择/修改,编出来的程序是不是个半身不遂的东西?这样的语言像不像被阉割过的太监?

  2、

  Quote:
输入为空时,我们采用
if /i "%source%"=="" goto ***
if /i "%source%"=="%*" goto ***
这个来解决。。
这样,当目标不存在的时候。。
可以及时获取错误信息进行修正。。

  可以说,判断输入是否为空是有好几种方法的,并且都能及时获取错误信息,比如还有 if not defined 语句。兄提供的方法在其他情况下确实可行,但是,兄可能没注意到上一标签段中的这个说明:

  Quote:
set source=:
:: 上面这句为后面去除引号做铺垫,冒号绝对不能省略;否则,当输入为空时按下回车会出错。

具体问题要具体分析,而不应只拘泥于固定的思维模式。

  3、

  Quote:
另外,当被复制文件运行或被占用的时候。
楼主有没有考虑写入日志(给出提示)然后再继续或停止复制呢?

  用重命名的方法似乎可以简单地判断文件是否在运行或被占用,不过,这个方法弊端很大:当要复制的文件比较多的时候,因为还要复原文件名,代码的执行效率会比较低下。在头几个版本中,我都会给备份后的文件加上"系统+只读"属性,到了这个版本,我已经取消了这个操作,执行效率问题也是其中的原因之一,所以,基于同样的原因,不打算增加这个功能。如果大家觉得有必要的话,在后续版本中将添加。

  4、

  Quote:
至于非法字符也非常好防御,写一个子程序。
利用 %data:~0,1% 类似的代码就可以搞定。。

  关于非法字符的防御,似乎并不像兄所说的那样简单,具体原因请参考本帖13楼 willsort 的分析。

  5、

  Quote:
楼主,请不要把这个做为最终代码吧:)
还有大量需要更新呢:)
呵呵,吃饭后再分析你的代码。

  对于兄的耐心分析,在此谢过,更多的不足需要包括像兄这样有耐心的人来测试才会发现得了(比如第3点)。但是,正如我在更新历史中所说的,如果这个版本没有太大的bug的话,我将不再更新代码,因为我目前的精力稍显有限,不能再对无关紧要的细节做更深入的考虑。
作者: flyinspace     时间: 2007-4-9 22:58


  Quote:
Originally posted by namejm at 2007-4-9 08:57 AM:
  1、
  从你的其他回帖可以看出,兄是编程中人,但是却说出这样的话,未免让人感到意外,试问:在面向对象的高级语言中,如果不提供对象 ...

晕,因为你违反了批处理的一个特性,简单快捷。。

而加参数正是为了这样一个目的而来。。要不然,我还不如直接使用 xcopy来得简单。

加了参数后,我们可以使用

批处理.cmd [源文件] [目标文件] [开关] ……

这样,才能省下工作量。。做批处理的目的是:让工作更加快捷而不是让工作更加麻烦,我才有此话。

最开始,我本准备提议使用.ini文件的。

想一下,我们第一次使用的时候是为好玩。第二次使用的时候是为新鲜感还没有过去。那么我们第n次使用的时候,有什么理由还要如此麻烦自己呢?

所以,我现在只要写的是关于实用一级的批处理,全部都加有参数。

这才有这句话的存在。
作者: flyinspace     时间: 2007-4-9 23:03
  4、


  Quote:
至于非法字符也非常好防御,写一个子程序。
利用 %data:~0,1% 类似的代码就可以搞定。。



  关于非法字符的防御,似乎并不像兄所说的那样简单,具体原因请参考本帖13楼 willsort 的分析。

至于源文件,我们没有必要在批处理中把这些判断完成。。

因为 微软在设计之初就把这些参数考虑到了。

我们所要做的只是捕捉这种错误就可以了。
作者: namejm     时间: 2007-4-9 23:56
Re flyinspace 『第 106 楼』和 『第 107 楼』:

  原以为你的意思是说如果不在代码中写那么多参数,则这个脚本就是废物一个,但是从你的这两个回帖来看,才发现你是说希望调用脚本的时候能加参数,看来是我误解了。

  但是,批处理.cmd [源文件] [目标文件] [开关] 的调用格式会有较多的参数需要学习,像我这等懒惰的菜鸟肯定会望而生畏的。用参数对程序员来说很方便,但是对普通用户来说就是一种折磨了,所以,我写这个脚本的初衷是:让用户跟着提示一步一步往下走,傻瓜式操作——我想,没有哪个备份狂会一天N次地频繁使用这个脚本来备份文件吧?如果有大量的备份操作或者备份要求很高的话,建议使用高级语言编写的专用备份程序,不推荐使用这个脚本。因此,这个脚本的定位决定了它的操作方式。

  因为这个脚本提供了手工输入和鼠标拖曳两种方式,对于拖曳方式,则完全不用检测特殊字符,这我是承认的,但是手工输入就很难保证用户不会输入特殊字符了,比如:万一在一些地方使用了重定向符号,则极有可能把重要文件给覆盖掉;为了保险起见,对特殊字符做检测是必要的。
作者: vkill     时间: 2007-4-10 01:08
其实不一定每个bat都要带参数的啊~
作者: namejm     时间: 2007-5-28 22:27


  Quote:
Originally posted by willsort at 2006-5-24 02:47:
Re namejm:
以下的语句可以剔除路径中可能存在的引号,将相对路径转换为绝对路径,将非标准路径转换为标准路径(C:\\-->C:\),并判断路径是否有效地存在,是否是根路径。 不过它仍无法抵抗路径中出现的非法字符(>|),不知其他兄弟还有什么更好的办法没有?

  这个问题困扰了我很久,一直到现在我才找到一个比较完美的方案,那就是:通过在%tmp%目录下创建随机文件夹,把判断非法字符的任务交给操作系统去完成。不过,让我感到有点不爽的是:这个方案产生了我一向力图回避的临时文件。

  具体代码请参考这个帖子: 判断输入的文件名是否合法的批处理
作者: yh6688     时间: 2007-6-1 14:18
liehan
作者: sxj7     时间: 2007-6-27 17:41
好东西,支持一下
作者: liu3157551     时间: 2007-9-3 10:01
看都不敢看了^_^