将多个文件(不同名称)重命名并复制到一个带数字的名称

Rename & Copy Multiple Files (Different names) to One Name With Numbers

我如何重命名或复制多个文件(具有不同的名称,没有数字,如 "jhf.mp4" "JJHGF.flv" ..)到一个带有数字的名称,如 (input_01.mp4 input_02 ....) (按情况排序)通过批处理文件,只需将(文件夹文件)的路径提供给批处理文件或将文件拖放到其中(补丁文件)。 -- 平均使用变量或(用 %* 删除).

注意 1:我需要这种使用 X264 编码动画的技术,如果有任何其他好的想法,我会很高兴听到。

注2:我用的是Windows10.

我认为你可以使用 WSHost-scripts 解决这个问题。 WSHost-system 应预装在任何现代 Windows 计算机上。


我设计了一个实用程序系统来解决您的问题:

  1. build-mapping-to-normalized-filenames.js

  2. map-filenames.js

  3. cleanup.cmd

  4. before.cmd

  5. after.cmd

您可以在这个答案的底部找到 3-4-5 的源代码,1-2 的源代码在单独的答案中(每个答案有字符数限制)。

1 和 2 是该系统的主力。强大而不是user-friendly。是的,如果您了解它们使用的输入,您可以将它们用作 stand-alone 实用程序。

3-4-5 - 是绑定此系统并公开 user-friendly 控件的粘合剂。

此系统依赖于绝对路径。但是所有绝对路径都在 3-4-5 的开头设置为变量 - 所以如果你想重组系统 - 你需要在那里改变东西,而且只在那里。

这是在文件系统中的部署方式:

folders:
C:\     <- this is the root of system
C:\aOrig    <- folder for original files
C:\norm\    <- folder with files that are part of this system + temp folders
C:\norm\backend   <- place for non-user-friendly utilities

files:
C:\norm\backend\build-mapping-to-normalized-filenames.js
C:\norm\backend\map-filenames.js
C:\norm\after.cmd
C:\norm\before.cmd
C:\norm\cleanup.cmd

+files: (these are example international filesnames that you can use for playground to check how system works to make yourserf familiar with it)
C:\aOrig\English.txt     <- test files, you could add unique content to each
C:\aOrig\Русский.txt
C:\aOrig\العربية.txt
C:\aOrig\ܐܪܡܝܐ.txt
C:\aOrig\中文.txt
C:\aOrig\日本語.txt

使用方法:

您打开控制台并转到目录 **C:\norm**

您按以下顺序调用程序:

  1. cleanup.cmd

  2. before.cmd

  3. 现在发生的是创建了两个有趣的临时文件夹:

    • C:\norm\bTemp <- 这里是标准化文件。

    • C:\norm\mappingTemp <- 它包含一个在原始名称和规范化名称之间进行映射的文件。

    您现在必须做的 - 是处理 C:\norm\bTemp 中的文件 - 您之前提到的特殊处理。现在出于学习目的,您可以手动更改扩展名和内容。

  4. after.cmd

  5. cleanup.cmd

就是这样。

所以,如果我们相信这就是您在这里的典型 session,简单明了 -

cleanup.cmd
before.cmd
..do your stuff with files at "C:\norm\bTemp"...
after.cmd
cleanup.cmd

此外,您不需要命令行来使用它们 - 您可以在资源管理器中打开 **C:\norm** 并按照我上面解释的顺序双击这些实用程序 - cleanup-before-(..用 bTemp 手动完成你的工作..)-after-cleanup


程序清单 cleanup.cmd :

@ECHO OFF

:: name of this script...
:: useful for debugging...
SET me=%~nx0

:: aOrig - directory that contains source files...
:: bTemp - temporary working directory...
:: mTemp - temporary directory for mapping.txt...
SET aOrig=C:\aOrig
SET bTemp=C:\norm\bTemp
SET mTemp=C:\norm\mappingTemp


:: Removing temporary folders...
:: Be warned - this RD is working
:: in quiet mode /Q - so it wouldn't ask you politely
:: about del y/n - thus, please make shure that
:: %aOrig% doesn't point to anything
:: important for your personal data or system...
    IF EXIST "%bTemp%" RD /S /Q "%bTemp%"
    IF EXIST "%mTemp%" RD /S /Q "%mTemp%"

    IF %ERRORLEVEL% NEQ 0 (
        ECHO Script %me% failed on step cleanup-1: [Removing temporary folders]...
        ECHO Error: %ERRORLEVEL%
        EXIT /B 1
    )

:: Successfully finished
    ECHO.
    ECHO Script %me% successfully finished!

程序列表 before.cmd :

@ECHO OFF

:: name of this script...
:: useful for debugging...
SET me=%~nx0

:: aOrig - directory that contains original files...
:: bTemp - temporary working directory...
:: mTemp - temporary directory for mapping.txt...
SET aOrig=C:\aOrig
SET bTemp=C:\norm\bTemp
SET mTemp=C:\norm\mappingTemp

:: scriptBuild - name of .js-script for building a map
::               from original to normalized filenames...
:: scriptMapFi - name of .js-script interpreting
::               mapping file that was build by scriptBuild...
:: mappingFile - path for file that will contain mapping between
::               original filenames and normalized filenames...
SET scriptBuild=C:\norm\backend\build-mapping-to-normalized-filenames.js
SET scriptMapFi=C:\norm\backend\map-filenames.js
SET mappingFile=C:\norm\mappingTemp\mapping.txt

:: creating temporary folders...
    IF NOT EXIST "%bTemp%" MKDIR "%bTemp%"
    IF NOT EXIST "%mTemp%" MKDIR "%mTemp%"
    IF %ERRORLEVEL% NEQ 0 (
        ECHO Script %me% failed on step before-1: [Creating temporary folders]...
        ECHO Error: %ERRORLEVEL%
        EXIT /B 1
    )

:: now we run build-mapping-to-normalized-filenames.js ...
:: that //U thing is important...
    CSCRIPT //U //NoLogo "%scriptBuild%" "%aOrig%" 0 1 > "%mappingFile%"
    IF %ERRORLEVEL% NEQ 0 (
        ECHO Script %me% failed on step before-2: [Building a list of normalized filenames]...
        ECHO Error: %ERRORLEVEL%
        EXIT /B 1
    )

:: now we run map-filenames.js ...
:: that //U thing is important...
    CSCRIPT //U //NoLogo "%scriptMapFi%" "%aOrig%" "%bTemp%" /NotTraining < "%mappingFile%"
    IF %ERRORLEVEL% NEQ 0 (
        ECHO Script %me% failed on step before-3: [Copy files while simultaneously changing their names to normalised form]...
        ECHO Error: %ERRORLEVEL%
        EXIT /B 1
    )

:: Successfully finished
    ECHO.
    ECHO Script %me% successfully finished!

程序清单 after.cmd :

@ECHO OFF

:: name of this script...
:: useful for debugging...
SET me=%~nx0

:: aOrig - directory that contains original files...
:: bTemp - temporary working directory...
:: mTemp - temporary directory for mapping.txt...
SET aOrig=C:\aOrig
SET bTemp=C:\norm\bTemp
SET mTemp=C:\norm\mappingTemp

:: scriptBuild - name of .js-script for building a map
::               from original to normalized filenames...
:: scriptMapFi - name of .js-script interpreting
::               mapping file that was build by scriptBuild...
:: mappingFile - path for file that will contain mapping between
::               original filenames and normalized filenames...
SET scriptBuild=C:\norm\backend\build-mapping-to-normalized-filenames.js
SET scriptMapFi=C:\norm\backend\map-filenames.js
SET mappingFile=C:\norm\mappingTemp\mapping.txt

:: Removing files in original folder...
:: Not recursive
:: Be warned - this DEL is working
:: in quiet mode /Q - so it wouldn't ask you politely
:: about del y/n - thus, please make shure that
:: %aOrig% doesn't point to anything
:: important for your personal data or system...
    IF EXIST "%aOrig%" DEL /Q "%aOrig%"

    IF %ERRORLEVEL% NEQ 0 (
        ECHO Script %me% failed on step after-1: [Removing files from original folder]...
        ECHO Error: %ERRORLEVEL%
        EXIT /B 1
    )

:: now we run map-filenames.js ...
:: that //U thing is important...
    CSCRIPT //U //NoLogo "%scriptMapFi%" "%bTemp%" "%aOrig%" /NotTraining /MapFrom2To1 /ResultExtension:2 /FuzzyExtensionsFrom < "%mappingFile%"
    IF %ERRORLEVEL% NEQ 0 (
        ECHO Script %me% failed on step after-2: [Copy files while simultaneously changing their names to normalised form]...
        ECHO Error: %ERRORLEVEL%
        EXIT /B 1
    )

:: Successfully finished
    ECHO.
    ECHO Script %me% successfully finished!

程序列表 build-mapping-to-normalized-filenames.js :

// - - - - -
//  #magicVars #config

// Purpose of basicOptions: organize set of most basic settings
//                          into a compact object package

var basicOptions = {

    // Fist things first -
    // "scriptName" will be important for error messages.
    // Because when you debug a pipeline of scripts, it is always
    // crucial to know - which program in pipeline of 10 utilities
    // throws that cryptic stderr message "error: not enough arguments".
    // I mean huh? Was that calc-tool.js? Or sort-tool.js? Go figure...
    scriptName: WScript.ScriptName.toString(),

    // What kind of End Of Line sequence
    // (they call it New Line sometimes too)
    // you prefer when using outputToolbox?
    eolStdOut: '\r\n',
    eolStdErr: '\r\n',

    // Those are all possible errorCodes that this script
    // was designed to fail with.
    // You can define other error codes.
    // Those SHOULD be integer (not strings).
    // Code noErrors = 0 is indication that script finished without errors.
    errorCodes: {
        noErrors: 0,
        badArguments: 1,
        badGettingFileList: 2
    }

};



// - - - - -

//  thisOptions

// Purpose of thisOptions: organize set of hard-coded
//                         normalisation settings
//                         into a compact object package

var thisOptions = {
    normNameBefore: 'input_',
    normNameAfter: ''
}



// - - - - -
//  outputToolbox depends on
//      basicOptions && WScript

// Purpose of outputToolbox: organize in one group
//                           functions that are used to
//                           output chars or messages to stdout or stderr

var outputToolbox = {

    // Syntactic sugar for printing exact set of chars to stdout.
    print: function( data ) {

        // For this script to output UTF characters correctly, program must
        // run under /U switch - like
        // cscript /U //NoLogo program-name-here.js arg1 arg2
        WScript.StdOut.Write( data );
    },

    // Syntactic sugar for printing one line to stdout.
    // terminated with your preferred line-terminator.
    printLine: function( data ) {
        outputToolbox.print( data );
        outputToolbox.print( basicOptions.eolStdOut );
    },

    // Syntactic sugar for printing exact set of chars to stderr.
    printErr: function( data ) {
        WScript.StdErr.Write( data );
    },

    // Syntactic sugar for printing one line to stderr
    // terminated with your preferred line-terminator.
    printErrLine: function( data ) {
        outputToolbox.printErr( data );
        outputToolbox.printErr( basicOptions.eolStdErr );
    },

    // Syntactic sugar for printing one line to stderr
    // prepended with meaningful script name (that is useful for debug)
    // terminated with your preferred line-terminator.
    printErrMessage: function( data ) {
        outputToolbox.printErr( basicOptions.scriptName + ' failed' );
        outputToolbox.printErr( data );
        outputToolbox.printErr( basicOptions.eolStdErr );
    },

    // Syntactic sugar for printing one line to stderr
    // prepended with meaningful script name (that is useful for debug)
    // terminated with your preferred line-terminator.
    printErrWarning: function( data ) {
        outputToolbox.printErr( 'Warning for ' + basicOptions.scriptName + ': ' );
        outputToolbox.printErr( data );
        outputToolbox.printErr( basicOptions.eolStdErr );
    },

    // Syntactic sugar for printing Error objects
    // catched by throw...catch construction
    printErrCatchedErr: function( e ) {
        outputToolbox.printErrMessage(
            ' - catched error details - ' + e.name + ': ' + e.message
        );
    }

};



// - - - - -
//  flowToolbox depends on
//      WScript

// Purpose of flowToolbox: organize in one group
//                         functions that are used to
//                         control general flow of program

var flowToolbox = {

    // Shortcut to kill this script.
    // When invoked it stops execution.
    die: function ( code ) {
        if ( typeof code === 'undefined' ) {
            code = 0;
        }
        WScript.Quit(code);
    }

};





// - - - - -
// Here is a cleaner alternative: we pollute only name $b.
// Not so easy to type but later, you can easily find all code calls
// dependant on functions from 'basis'.
// '$b' stands for 'library-b' or more exactly - "library named 'basis'"

var $b = {};

$b.print           = outputToolbox.print;
$b.printLine       = outputToolbox.printLine;
$b.printErr        = outputToolbox.printErr;
$b.printErrLine    = outputToolbox.printErrLine;
$b.printErrMessage = outputToolbox.printErrMessage;
$b.printErrWarning = outputToolbox.printErrWarning;

$b.die             = flowToolbox.die;

// ^ You can use those as functions now





// - - - - -
//  $fileListToolbox
//      depends on WScript && ActiveXObject( "Scripting.FileSystemObject" ) && $b

var $fileListToolbox = {

    /*
    *   Input:
    *       any gibberish that is acceptable
    *       for your local version of
    *       Scripting.FileSystemObject
    *       - like
    *           getFileListForFolder( 'C:\' );
    *           getFileListForFolder( 'C:\abc' );
    *           getFileListForFolder( './' );
    *           getFileListForFolder( './abc/../abc/..' );
    *   
    *   Output:
    *       aFileList with format:
    *           empty array
    *           or
    *           array of oFileData
    *               oFileData has format:
    *               {
    *                   fileNameBase:       ...[string],
    *                   fileNameExtension:  ...[string],
    *                   parentAbsolutePath: ...[string]
    *               }
    */
    getFileListForFolder: function( folderSpec )
    {
        var aResult = [];

        var fso    = new ActiveXObject( "Scripting.FileSystemObject" );

        if ( !fso.FolderExists( folderSpec ) ) {
            $b.printErrMessage(' folder="' + folderSpec + '" doesn\'t exist');
            $b.die( basicOptions.errorCodes.badGettingFileList );
        }

        var folder = fso.GetFolder( folderSpec );
        var files  = new Enumerator( folder.files );

        for ( ; !files.atEnd(); files.moveNext() ) {

            var thisFileItem = files.item();
            aResult.push({
                fileNameBase:      fso.GetBaseName(      thisFileItem ),
                fileNameExtension: fso.GetExtensionName( thisFileItem ),

                parentAbsolutePath: (
                    fso.GetParentFolderName(
                        fso.GetAbsolutePathName( thisFileItem )
                    )
                )
            });

        }
        return( aResult );
    },


    /*
    *   Purpose:
    *       Sort files by fileNameBase
    *   
    *   Input:
    *       aFileList
    *           - format is the same
    *           as for function $fileListToolbox.getFileListForFolder
    *   
    *   Output:
    *       - format is the same
    *       as for function $fileListToolbox.getFileListForFolder
    */
    sortFileListByFileNameBaseAsc: function( aFileList ) {

        var fSort = function( a, b ) {
            if ( a.fileNameBase > b.fileNameBase ) {
                return 1;
            }
            if ( a.fileNameBase < b.fileNameBase ) {
                return -1;
            }
            return 0;
        }

        return aFileList.sort( fSort );

    },


    /*
    *   Purpose:
    *       Tool for displaying contents of fileList
    *   
    *   Input:
    *       aFileList
    *           - format is the same
    *           as for function $fileListToolbox.getFileListForFolder
    *   
    *   Sideeffects:
    *       Prints aFileList to the stdout stream
    */
    printFileList: function( aFileList, callbackPrintLine ) {

        if ( typeof callbackPrintLine === 'undefined' ) {
            return;
        }

        var i;
        var L = aFileList.length;
        var elem;
        for ( i = 0; i < L; i++ ) {
            elem = aFileList[i];
            callbackPrintLine();
            callbackPrintLine( 'i: ' + i );
            callbackPrintLine( 'fileNameBase:       ' + elem.fileNameBase );
            callbackPrintLine( 'fileNameExtension:  ' + elem.fileNameExtension );
            callbackPrintLine( 'parentAbsolutePath: ' + elem.parentAbsolutePath );
        }
    }

};

/*
// basic test:
$fileListToolbox.printFileList(
    $fileListToolbox.sortFileListByFileNameBaseAsc(
        $fileListToolbox.getFileListForFolder( 'bTmp' )
    ),
    $b.printLine
);
*/














// - - - - -
//  $mappingEngine

var $mappingEngine = {

    // this is a relic from a more complex fileformat...
    printHeader: function(
        functionPrintChars
    ) {
    },

    printBasicFilePair: function(
        functionPrintChars,
        aFileNameBase, aFileNameExtension,
        bFileNameBase, bFileNameExtension
    ) {
        var eol = '\r\n';

        if ( aFileNameBase.match( /[\r\n]/ ) !== null ) {
            throw new Error(
                'error: bad input: aFileNameBase contains end of line symbols'
            );
        }
        if ( bFileNameBase.match( /[\r\n]/ ) !== null ) {
            throw new Error(
                'error: bad input: bFileNameBase contains end of line symbols'
            );
        }
        if ( aFileNameExtension.match( /[\r\n]/ ) !== null ) {
            throw new Error(
                'error: bad input: aFileNameExtension contains end of line symbols'
            );
        }
        if ( bFileNameExtension.match( /[\r\n]/ ) !== null ) {
            throw new Error(
                'error: bad input: bFileNameExtension contains end of line symbols'
            );
        }

        var ar = [
            'id:1',
            'baseName:'      + aFileNameBase,
            'extensionName:' + aFileNameExtension,
            'id:2',
            'baseName:'      + bFileNameBase,
            'extensionName:' + bFileNameExtension,
            ':',
            ''
        ];
        functionPrintChars( ar.join( eol ) );
    }

};

/*
//basic test:
$mappingEngine.printHeader( $b.print );
$mappingEngine.printBasicFilePair( $b.print, 'abcdef', 'ext', 'input_001', 'txt' );
$mappingEngine.printBasicFilePair( $b.print, 'ghijkl', 'jpg', 'input_002', 'png' );
*/
// it should print to output:
/*
id:1
baseName:abcdef
extensionName:ext
id:2
baseName:input_001
extensionName:txt
:
id:1
baseName:ghijkl
extensionName:jpg
id:2
baseName:input_002
extensionName:png
:

*/





// - - - - -

function generateFAddLeadingZeroes( minimumLength, startFrom ) {

    if ( typeof minimumLength === 'undefined' ) {
        minimumLength = 0;
    }
    if ( typeof startFrom === 'undefined' ) {
        startFrom = 0;
    }

    minimumLength = parseInt( minimumLength ) - 1;
    startFrom     = parseInt( startFrom );

    var fAddLeadingZeroes = function( i, L ) {

        i += startFrom;
        L += startFrom - 1;

        var sResult = i.toString();

        if ( minimumLength > 0 ) {

            var level = 0;
            var tmpL = L;
            while (
                ( tmpL = parseInt( tmpL / 10 ) ) >= 1
            ) {
                ++level;
            }

            level = Math.max( level, minimumLength );

            var iLength = sResult.length;
            while ( iLength <= level-- ) {
                sResult = '0' + sResult;
            }
        }

        return sResult;
    }
    return fAddLeadingZeroes;
}





// - - - - -
var $thisArguments = {

    getArgumentsObj: function() {

        return WScript.Arguments;


        // mockup for tests in browser
        /*
        var testArr = [1,2,3,4,5];
        var mockupArguments = function( i ) {
            return testArr[i];
        };
        mockupArguments.length = testArr.length;
        return mockupArguments;
        */
    },

    printErrorMessageAndDie: function( meaningfulPart ) {
        $b.printErrMessage(
            ' - problem when ' +
            'parsing command-line arguments (options): ' +
            ''
        );
        $b.die( basicOptions.errorCodes.badArguments );
    },

    getArgumentsDummy: function() {
        return {
            folder:       'C:\abc',
            minNOfDigits: 0,
            countStart:   1
        };
    },

    print: function( argumentsObject ) {
        $b.printErrLine( 'folder:       ' + argumentsObject.folder       );
        $b.printErrLine( 'minNOfDigits: ' + argumentsObject.minNOfDigits );
        $b.printErrLine( 'countStart:   ' + argumentsObject.countStart   );
    },

    // We don't use any flags it this script...
    /*
    isThereAFlagInArguments: function( inString ) {
        var normalizedEthalon = inString.toString().toLowerCase();
        var objArgs = $thisArguments.getArgumentsObj();
        var i;
        var L = objArgs.length;
        for ( i = 2; i < L; i++ ) {
            var normalizedArgument = objArgs( i ).toString().toLowerCase();
            if ( normalizedEthalon === normalizedArgument ) {
                return true;
            }
        }
        return false;
    },
    */

    getArguments: {

        folder: function() {
            var rR = '';
            var objArgs = $thisArguments.getArgumentsObj();
            if ( objArgs.length < 1 ) {
                $b.printErrMessage(
                    ' - reason: not enough arguments, ' +
                    'you MUST to provide at least 1 argument, ' +
                    'but ammount of arguments you provided ' +
                    'only: ' + objArgs.length
                );
                $b.die( basicOptions.errorCodes.badArguments );
            }

            rR = objArgs(0);

            var fso = new ActiveXObject("Scripting.FileSystemObject");
            rR = fso.GetAbsolutePathName( rR );

            return rR;
        },

        minNOfDigits: function() {
            var rR = '0';
            var objArgs = $thisArguments.getArgumentsObj();

            if ( objArgs.length >= 2 ) {
                rR = objArgs(1);
            }

            var intRR = parseInt( rR );

            // test for NaN
            if ( intRR !== intRR ) {
                $b.printErrMessage(
                    ' - reason: bad argument 2, ' +
                    'you MUST to provide non-negative integer, ' +
                    'but you provided non-integer: ' +
                    '[' + ( typeof rR ) + ']' +
                    ' "' + rR + '"' +
                    ''
                );
                $b.die( basicOptions.errorCodes.badArguments );
            }

            // test for negative
            if ( intRR < 0 ) {
                $b.printErrMessage(
                    ' - reason: bad argument 2, ' +
                    'you MUST to provide non-negative integer, ' +
                    'but you provided negtive integer: ' +
                    '[' + ( typeof rR ) + ']' +
                    ' "' + rR + '"' +
                    ''
                );
                $b.die( basicOptions.errorCodes.badArguments );
            }

            rR = intRR;

            return rR;
        },

        countStart: function() {
            var rR = '1';
            var objArgs = $thisArguments.getArgumentsObj();
            if ( objArgs.length >= 3 ) {
                rR = objArgs(2);
            }

            var intRR = parseInt( rR );

            // test for NaN
            if ( intRR !== intRR ) {
                $b.printErrMessage(
                    ' - reason: bad argument 3, ' +
                    'you MUST to provide non-negative integer, ' +
                    'but you provided non-integer: ' +
                    '[' + ( typeof rR ) + ']' +
                    ' "' + rR + '"' +
                    ''
                );
                $b.die( basicOptions.errorCodes.badArguments );
            }

            // test for negative
            if ( intRR < 0 ) {
                $b.printErrMessage(
                    ' - reason: bad argument 3, ' +
                    'you MUST to provide non-negative integer, ' +
                    'but you provided negtive integer: ' +
                    '[' + ( typeof rR ) + ']' +
                    ' "' + rR + '"' +
                    ''
                );
                $b.die( basicOptions.errorCodes.badArguments );
            }

            rR = intRR;

            return rR;
        }

    },

    getArgumentsAll: function() {
        var $get = $thisArguments.getArguments;

        var rR = {
            folder:       $get.folder(),
            minNOfDigits: $get.minNOfDigits(),
            countStart:   $get.countStart()
        };

        return rR;
    }

};

var $a = $thisArguments;





// - - - - -

function main() {

    var $inputOptions = $a.getArgumentsAll();
    $b.printErrLine();
    $b.printErrLine(
        'Arguments for ' + basicOptions.scriptName +
        ' are interpreted this way:'
    );
    $a.print( $inputOptions );
    $b.printErrLine();

    try {
        var aFileList = $fileListToolbox.getFileListForFolder( $inputOptions.folder );
    } catch (e) {
        $b.printErrMessage(
            ' - problems while trying ' +
            'to get list of files from folder: ' +
            $inputOptions.folder
        );
        $b.die( basicOptions.errorCodes.badGettingFileList );
        return;
    }
    aFileList = $fileListToolbox.sortFileListByFileNameBaseAsc( aFileList );

    // addLeadingZeroes
    // is a function now.
    // You can see what arguments it requires
    // and output it produces in source for
    // generateFAddLeadingZeroes
    // function.
    var addLeadingZeroes = generateFAddLeadingZeroes(
        $inputOptions.minNOfDigits,
        $inputOptions.countStart
    );

    var normNameBefore = thisOptions.normNameBefore;
    var normNameAfter  = thisOptions.normNameAfter;

    var i;
    var L = aFileList.length;
    for ( i = 0; i < L; i++ ) {

        var elem = aFileList[i];

        var aBase      = elem.fileNameBase;
        var aExtension = elem.fileNameExtension;

        var count      = addLeadingZeroes( i, L );

        var bBase      = normNameBefore + count + normNameAfter;
        var bExtension = aExtension;

        $mappingEngine.printBasicFilePair(
            $b.print,
            aBase, aExtension,
            bBase, bExtension
        );
    }

    $b.printErr( 'Script ' + basicOptions.scriptName + ' - finished!' );

};

main();

程序清单 map-filenames.js :

// - - - - -
//  #magicVars #config

// Purpose of basicOptions: organize set of most basic settings
//                          into a compact object package

var basicOptions = {

    // Fist things first -
    // "scriptName" will be important for error messages.
    // Because when you debug a pipeline of scripts, it is always
    // crucial to know - which program in pipeline of 10 utilities
    // throws that cryptic stderr message "error: not enough arguments".
    // I mean huh? Was that calc-tool.js? Or sort-tool.js? Go figure...
    scriptName: WScript.ScriptName.toString(),

    // What kind of End Of Line sequence
    // (they call it New Line sometimes too)
    // you prefer when using outputToolbox?
    eolStdOut: '\r\n',
    eolStdErr: '\r\n',

    // Those are all possible errorCodes that this script
    // was designed to fail with.
    // You can define other error codes.
    // Those SHOULD be integer (not strings).
    // Code noErrors = 0 is indication that script finished without errors.
    errorCodes: {
        noErrors: 0,
        badArguments: 1,
        badCopy: 2,
        badParsing: 3,
        badGettingFileList: 4
    }

};



// - - - - -



// - - - - -
//  outputToolbox depends on
//      basicOptions && WScript

// Purpose of outputToolbox: organize in one group
//                           functions that are used to
//                           output chars or messages to stdout or stderr

var outputToolbox = {

    // Syntactic sugar for printing exact set of chars to stdout.
    print: function( data ) {

        // For this script to output UTF characters correctly, program must
        // run under /U switch - like
        // cscript /U //NoLogo program-name-here.js arg1 arg2
        WScript.StdOut.Write( data );
    },

    // Syntactic sugar for printing one line to stdout.
    // terminated with your preferred line-terminator.
    printLine: function( data ) {
        outputToolbox.print( data );
        outputToolbox.print( basicOptions.eolStdOut );
    },

    // Syntactic sugar for printing exact set of chars to stderr.
    printErr: function( data ) {
        WScript.StdErr.Write( data );
    },

    // Syntactic sugar for printing one line to stderr
    // terminated with your preferred line-terminator.
    printErrLine: function( data ) {
        outputToolbox.printErr( data );
        outputToolbox.printErr( basicOptions.eolStdErr );
    },

    // Syntactic sugar for printing one line to stderr
    // prepended with meaningful script name (that is useful for debug)
    // terminated with your preferred line-terminator.
    printErrMessage: function( data ) {
        outputToolbox.printErr( basicOptions.scriptName + ' failed' );
        outputToolbox.printErr( data );
        outputToolbox.printErr( basicOptions.eolStdErr );
    },

    // Syntactic sugar for printing one line to stderr
    // prepended with meaningful script name (that is useful for debug)
    // terminated with your preferred line-terminator.
    printErrWarning: function( data ) {
        outputToolbox.printErr( 'Warning for ' + basicOptions.scriptName + ': ' );
        outputToolbox.printErr( data );
        outputToolbox.printErr( basicOptions.eolStdErr );
    },

    // Syntactic sugar for printing Error objects
    // catched by throw...catch construction
    printErrCatchedErr: function( e ) {
        outputToolbox.printErrMessage(
            ' - catched error details - ' + e.name + ': ' + e.message
        );
    }

};



// - - - - -
//  flowToolbox depends on
//      WScript

// Purpose of flowToolbox: organize in one group
//                         functions that are used to
//                         control general flow of program

var flowToolbox = {

    // Shortcut to kill this script.
    // When invoked it stops execution.
    die: function ( code ) {
        if ( typeof code === 'undefined' ) {
            code = 0;
        }
        WScript.Quit(code);
    }

};





// - - - - -
// Here is a cleaner alternative: we pollute only name $b.
// Not so easy to type but later, you can easily find all code calls
// dependant on functions from 'basis'.
// '$b' stands for 'library-b' or more exactly - "library named 'basis'"

var $b = {};

$b.print           = outputToolbox.print;
$b.printLine       = outputToolbox.printLine;
$b.printErr        = outputToolbox.printErr;
$b.printErrLine    = outputToolbox.printErrLine;
$b.printErrMessage = outputToolbox.printErrMessage;
$b.printErrWarning = outputToolbox.printErrWarning;

$b.die             = flowToolbox.die;

// ^ You can use those as functions now





// - - - - -
//  $fileListToolbox
//      depends on WScript && ActiveXObject( "Scripting.FileSystemObject" ) && $b

var $fileListToolbox = {

    /*
    *   Input:
    *       any gibberish that is acceptable
    *       for your local version of
    *       Scripting.FileSystemObject
    *       - like
    *           getFileListForFolder( 'C:\' );
    *           getFileListForFolder( 'C:\abc' );
    *           getFileListForFolder( './' );
    *           getFileListForFolder( './abc/../abc/..' );
    *   
    *   Output:
    *       aFileList with format:
    *           empty array
    *           or
    *           array of oFileData
    *               oFileData has format:
    *               {
    *                   fileNameBase:       ...[string],
    *                   fileNameExtension:  ...[string],
    *                   parentAbsolutePath: ...[string]
    *               }
    */
    getFileListForFolder: function( folderSpec )
    {
        var aResult = [];

        var fso    = new ActiveXObject( "Scripting.FileSystemObject" );

        if ( !fso.FolderExists( folderSpec ) ) {
            $b.printErrMessage(' folder="' + folderSpec + '" doesn\'t exist');
            $b.die( basicOptions.errorCodes.badGettingFileList );
        }

        var folder = fso.GetFolder( folderSpec );
        var files  = new Enumerator( folder.files );

        for ( ; !files.atEnd(); files.moveNext() ) {

            var thisFileItem = files.item();
            aResult.push({
                fileNameBase:      fso.GetBaseName(      thisFileItem ),
                fileNameExtension: fso.GetExtensionName( thisFileItem ),

                parentAbsolutePath: (
                    fso.GetParentFolderName(
                        fso.GetAbsolutePathName( thisFileItem )
                    )
                )
            });

        }
        return( aResult );
    },


    /*
    *   Purpose:
    *       Sort files by fileNameBase
    *   
    *   Input:
    *       aFileList
    *           - format is the same
    *           as for function $fileListToolbox.getFileListForFolder
    *   
    *   Output:
    *       - format is the same
    *       as for function $fileListToolbox.getFileListForFolder
    */
    sortFileListByFileNameBaseAsc: function( aFileList ) {

        var fSort = function( a, b ) {
            if ( a.fileNameBase > b.fileNameBase ) {
                return 1;
            }
            if ( a.fileNameBase < b.fileNameBase ) {
                return -1;
            }
            return 0;
        }

        return aFileList.sort( fSort );

    },

    /*
        Output:
            false
                when no results
            oFileData
                when result found
    */
    getAnyFileWithBaseName: function( baseName, aFileList ) {

        var i;
        var L = aFileList.length;
        for ( i = 0; i < L; i++ ) {
            var a = aFileList[i];
            if ( a.fileNameBase === baseName ) {
                return a;
            }
        }

        return false;
    },


    /*
    *   Purpose:
    *       Tool for displaying contents of fileList
    *   
    *   Input:
    *       aFileList
    *           - format is the same
    *           as for function $fileListToolbox.getFileListForFolder
    *   
    *   Sideeffects:
    *       Prints aFileList to the stdout stream
    */
    printFileList: function( aFileList, callbackPrintLine ) {

        if ( typeof callbackPrintLine === 'undefined' ) {
            return;
        }

        var i;
        var L = aFileList.length;
        var elem;
        for ( i = 0; i < L; i++ ) {
            elem = aFileList[i];
            callbackPrintLine();
            callbackPrintLine( 'i: ' + i );
            callbackPrintLine( 'fileNameBase:       ' + elem.fileNameBase );
            callbackPrintLine( 'fileNameExtension:  ' + elem.fileNameExtension );
            callbackPrintLine( 'parentAbsolutePath: ' + elem.parentAbsolutePath );
        }
    }

};

/*
// basic test:
$fileListToolbox.printFileList(
    $fileListToolbox.sortFileListByFileNameBaseAsc(
        $fileListToolbox.getFileListForFolder( 'bTmp' )
    ),
    $b.printLine
);
*/
/*
// test for fuzzy search only by file base name:
$fileListToolbox.printFileList(
    $fileListToolbox.sortFileListByFileNameBaseAsc(
        $fileListToolbox.getFileListForFolder( 'bTmp' )
    ),
    $b.printLine
);

var fuzzy = $fileListToolbox.getAnyFileWithBaseName(
    'input_1',
    $fileListToolbox.getFileListForFolder( 'bTmp' )
);

$b.printLine( 'fuzzy.fileNameBase:      ' + fuzzy.fileNameBase      );
$b.printLine( 'fuzzy.fileNameExtension: ' + fuzzy.fileNameExtension );
*/











// $streamToolbox

var $streamToolbox = {

    // when end of line returns '' (aka empty string)
    getChar: function() {
        if ( WScript.StdIn.AtEndOfStream ) {
            return '';
        }
        return WScript.StdIn.Read(1);
    },

    // tests show that for Windows 7 it understands terminators
    // CRLF or LF-only
    // when end of line returns '' (aka empty string)
    getLine: function() {
        if ( WScript.StdIn.AtEndOfStream ) {
            return '';
        }
        return WScript.StdIn.ReadLine();
    }

}

var $s = $streamToolbox;

// it could be used like that:
/*
var piece;
while ( ( piece = $s.getLine() ) !== '' ) {

    $b.printLine( 'piece: ' + '>' + piece + '<' );
}
*/









// $thisArguments

var $thisArguments = {

    getArgumentsObj: function() {

        return WScript.Arguments;


        // mockup for tests in browser
        /*
        var testArr = [1,2,3,4,5];
        var mockupArguments = function( i ) {
            return testArr[i];
        };
        mockupArguments.length = testArr.length;
        return mockupArguments;
        */
    },

    printErrorMessageAndDie: function( meaningfulPart ) {
        $b.printErrMessage(
            ' - problem when ' +
            'parsing command-line arguments (options): ' +
            ''
        );
        $b.die( basicOptions.errorCodes.badArguments );
    },

    getArgumentsDummy: function() {
        return {
            direction:            'from-id-2-to-id-1',
            resultExtension:      'auto',
            folderFrom:           'C:\abc',
            folderTo:             'D:\abc',
            mode:                 'training',
            modeForExtensionFrom: 'strict'
        };
    },

    print: function( argumentsObject ) {
        $b.printErrLine( 'folderFrom:           ' + argumentsObject.folderFrom           );
        $b.printErrLine( 'folderTo:             ' + argumentsObject.folderTo             );
        $b.printErrLine( 'direction:            ' + argumentsObject.direction            );
        $b.printErrLine( 'resultExtension:      ' + argumentsObject.resultExtension      );
        $b.printErrLine( 'mode:                 ' + argumentsObject.mode                 );
        $b.printErrLine( 'modeForExtensionFrom: ' + argumentsObject.modeForExtensionFrom );
    },

    isThereAFlagInArguments: function( inString ) {
        var normalizedEthalon = inString.toString().toLowerCase();
        var objArgs = $thisArguments.getArgumentsObj();
        var i;
        var L = objArgs.length;
        for ( i = 2; i < L; i++ ) {
            var normalizedArgument = objArgs( i ).toString().toLowerCase();
            if ( normalizedEthalon === normalizedArgument ) {
                return true;
            }
        }
        return false;
    },

    getArguments: {

        folderFrom: function() {
            var rR = '';
            var objArgs = $thisArguments.getArgumentsObj();
            if ( objArgs.length < 2 ) {
                $b.printErrMessage(
                    ' - reason: not enough arguments, ' +
                    'you MUST to provide at least 2 arguments, ' +
                    'but ammount of arguments you provided ' +
                    'is only: ' + objArgs.length
                );
                $b.die( basicOptions.errorCodes.badArguments );
            }

            rR = objArgs(0);

            var fso = new ActiveXObject("Scripting.FileSystemObject");
            rR = fso.GetAbsolutePathName( rR );

            return rR;
        },

        folderTo: function() {
            var rR = '';
            var objArgs = $thisArguments.getArgumentsObj();
            if ( objArgs.length < 2 ) {
                $b.printErrMessage(
                    ' - reason: not enough arguments, ' +
                    'you MUST to provide at least 2 arguments, ' +
                    'but ammount of arguments you provided ' +
                    'is only: ' + objArgs.length
                );
                $b.die( basicOptions.errorCodes.badArguments );
            }

            rR = objArgs(1);

            var fso = new ActiveXObject("Scripting.FileSystemObject");
            rR = fso.GetAbsolutePathName( rR );

            return rR;
        },

        direction: function() {
            var rR = 'from-id-1-to-id-2';
            var hasFlag = $thisArguments.isThereAFlagInArguments;
            if ( hasFlag( '/MapFrom2To1' ) ) {
                rR = 'from-id-2-to-id-1';
            }
            return rR;
        },

        resultExtension: function() {
            var rR = 'auto';
            var hasFlag = $thisArguments.isThereAFlagInArguments;
            if ( hasFlag( '/ResultExtension:none' ) ) {
                rR = 'none';
            }
            if ( hasFlag( '/ResultExtension:21' ) ) {
                rR = '21';
            }
            if ( hasFlag( '/ResultExtension:12' ) ) {
                rR = '12';
            }
            if ( hasFlag( '/ResultExtension:2' ) ) {
                rR = '2';
            }
            if ( hasFlag( '/ResultExtension:1' ) ) {
                rR = '1';
            }
            return rR;
        },

        mode: function() {
            var rR = 'training';
            var hasFlag = $thisArguments.isThereAFlagInArguments;
            if ( hasFlag( '/NotTraining' ) ) {
                rR = 'not-training';
            }
            return rR;
        },

        modeForExtensionFrom: function() {
            var rR = 'strict';
            var hasFlag = $thisArguments.isThereAFlagInArguments;
            if ( hasFlag( '/FuzzyExtensionsFrom' ) ) {
                rR = 'fuzzy';
            }
            return rR;
        }

    },

    getArgumentsAll: function() {
        var $get = $thisArguments.getArguments;

        var rR = {
            folderFrom:           $get.folderFrom(),
            folderTo:             $get.folderTo(),
            direction:            $get.direction(),
            resultExtension:      $get.resultExtension(),
            mode:                 $get.mode(),
            modeForExtensionFrom: $get.modeForExtensionFrom()
        };

        return rR;
    }

};

var $a = $thisArguments;

//you can use it like this:
/*
var $inputOptions = $a.getArgumentsAll()
$a.print( $inputOptions );
*/










// $parser

// mockup options for separate testing
/*
var basicOptions = {
    errorCodes: {
        badParsing: 3
    }
};

var $b = {
    printErrMessage: function( a ) { console.log(a); },
    die: function() { throw new Error(); }
};
*/

var $parser = {};

$parser.generateDummyLineReader = function( textBlock ) {
    var lines = textBlock.split( '\r\n' );
    var i = -1;
    var L = lines.length;

    var f = function() {
        i++;
        if ( i >= L ) {
            return '';
        }

        return lines[i];
    }

    return f;
}

$parser.generateDummyInputOptions = function() {
    return {
        direction: '1-to-2',
        resultExtension: '12',
        folderFrom: 'C:\abc',
        folderTo:   'D:\abc'
    }
}

$parser.generateDummyMappingLineReader = function() {
    return $parser.generateDummyLineReader(
        [
            'id:1',
            'baseName:abcdef',
            'extensionName:ext',
            'id:2',
            'baseName:input_001',
            'extensionName:txt',
            ':',
            'id:1',
            'baseName:ghijkl',
            'extensionName:jpg',
            'id:2',
            'baseName:input_002',
            'extensionName:png',
            ':'
        ].join('\r\n')
    );
}

/*
    Remark:
        functionReadNextLine
            must be iterator that returns '' (aka empty string)
            when stream of lines ends
        functionForEachBlockDo must have
        those arguments: 
            - id1Base
            - id1Ext
            - id2Base
            - id2Ext
            - $inputOptions
            - functionCopyFile
        $inputOptions must have properties
        (wherever it mentioned in this block of comments):
            - direction
            - resultExtension
            - folderFrom
            - folderTo
        functionCopyFile must have these arguments
            - folderFrom
            - fileFrom
            - folderTo
            - fileTo
*/
$parser.parseLinesAndForEachBlockDo = function(
    functionReadNextLine,
    functionForEachBlockDo,
    $inputOptions,
    functionCopyFile
) {
    var buffer = null;

    var nOfLine = 0;

    var states = [
        'waitingForId1',
        'waitingForId2',
        'waitingForBase',
        'waitingForExtension',
        'waitingForEndOfGroup'
    ];

    function printErrorMessageAndDie( meaningfulPart ) {
        $b.printErrMessage(
            ' - problem when parsing line ' + nOfLine + ': ' +
            '[' + typeof line + ']' +
            '"' + line + '"' +
            meaningfulPart +
            ''
        );
        $b.die( basicOptions.errorCodes.badParsing );
    }

    var state = 'waitingForId1';

    var line;

    while (
        ( line = functionReadNextLine() ) !== ''
    ) {
        ++nOfLine;

        var arOrNull = line.match( /^([a-zA-Z0-9-]*):(.*)$/ );

        if (
            ( arOrNull === null )
        ) {
            printErrorMessageAndDie(
                'every line in mapping must be either' +
                '"key:value" or ":"'
            );
        }

        var key   = arOrNull[1];
        var value = arOrNull[2];

        if (
            ( value.match( '\r' ) !== null )
        ) {
            printErrorMessageAndDie(
                'if line is ' +
                '"key:value" ' +
                'then it MUST NOT contain \r (CR) symbols ' +
                'exept in terminator'
            );
        }

        if ( state === 'waitingForId1' ) {
            if (
                ( key === 'id' )
                &&
                ( value === '1' )
            ) {
                buffer = {};
                buffer.nowGroup = {
                    id: 1
                };
                state = 'waitingForBase';
                continue;
            } else {
                printErrorMessageAndDie(
                    'but this line must be "id:1"'
                );
            }
        }

        if ( state === 'waitingForBase' ) {
            if (
                ( key === 'baseName' )
            ) {
                buffer.nowGroup.base = value;
                state = 'waitingForExtension';
                continue;
            } else {
                printErrorMessageAndDie(
                    'but this line must be "baseName:...anything-here..."'
                );
            }
        }

        if ( state === 'waitingForExtension' ) {
            if (
                ( key === 'extensionName' )
            ) {
                buffer.nowGroup.ext = value;
                if ( buffer.nowGroup.id === 1 ) {
                    state = 'waitingForId2';
                } else {
                    state = 'waitingForEndOfGroup';
                }
                continue;
            } else {
                printErrorMessageAndDie(
                    'but this line must be "extensionName:...anything-here..."'
                );
            }
        }

        if ( state === 'waitingForId2' ) {
            if (
                ( key === 'id' )
                &&
                ( value === '2' )
            ) {
                buffer.group1 = {
                    base: buffer.nowGroup.base,
                    ext: buffer.nowGroup.ext
                }
                buffer.nowGroup = {
                    id: 2
                };
                state = 'waitingForBase';
                continue;
            } else {
                printErrorMessageAndDie(
                    'but this line must be "id:2"'
                );
            }
        }

        if ( state === 'waitingForEndOfGroup' ) {
            if (
                ( key === '' )
                &&
                ( value === '' )
            ) {
                buffer.group2 = {
                    base: buffer.nowGroup.base,
                    ext: buffer.nowGroup.ext
                }

                functionForEachBlockDo(
                    buffer.group1.base,
                    buffer.group1.ext,
                    buffer.group2.base,
                    buffer.group2.ext,
                    $inputOptions,
                    functionCopyFile
                );
                buffer = null;

                state = 'waitingForId1';
                continue;
            } else {
                printErrorMessageAndDie(
                    'but this line must be ":"'
                );
            }
        }

    }

    if ( buffer !== null ) {
        printErrorMessageAndDie(
            'dangling state (not all properties group are defined) - ' + state
        );
    }
}
/*
// test
// can be tested in for browser with only $parser object
$parser.parseLinesAndForEachBlockDo(
    $parser.generateDummyMappingLineReader(),
    function( a, b, c, d ) {
        console.log( 'a:', a, 'b:', b, 'c:', c, 'd:', d );
    }
);
*/

/*
    Remark:
        $inputOptions must have properties:
            - direction
            - resultExtension
            - folderFrom
            - folderTo

*/
$parser.reactionOnGoodParsedBlock = function(
    id1Base, id1Ext,
    id2Base, id2Ext,
    $inputOptions,
    functionCopyFile
) {
    function glueExtensionToFileName(
        fileName, extension
    ) {
        fileName  = fileName.toString();
        extension = extension.toString();
        if ( extension.length > 0 ) {
            extension = '.' + extension;
        }
        return fileName + extension;
    }

    var folderFrom = $inputOptions.folderFrom;
    var folderTo   = $inputOptions.folderTo;

    if ( $inputOptions.modeForExtensionFrom === 'fuzzy' ) {

        var tmpFromBase = id1Base;
        if ( $inputOptions.direction == 'from-id-2-to-id-1' ) {
            tmpFromBase = id2Base;
        }

        var fuzzyFile = $fileListToolbox.getAnyFileWithBaseName(
            tmpFromBase,
            $fileListToolbox.getFileListForFolder( folderFrom )
        );

        if ( fuzzyFile !== false ) {
            if ( $inputOptions.direction == 'from-id-2-to-id-1' ) {
                id2Ext = fuzzyFile.fileNameExtension;
            } else {
                id1Ext = fuzzyFile.fileNameExtension;
            }
        }

    }

    var fromSet = { base: id1Base, ext: id1Ext };
    var toSet   = { base: id2Base, ext: id2Ext };

    if ( $inputOptions.direction == 'from-id-2-to-id-1' ) {
        fromSet = { base: id2Base, ext: id2Ext };
        toSet   = { base: id1Base, ext: id1Ext };
    }

    if ( $inputOptions.resultExtension === '21' ) {
        toSet.ext = glueExtensionToFileName( id2Ext, id1Ext );
    }
    if ( $inputOptions.resultExtension === '12' ) {
        toSet.ext = glueExtensionToFileName( id1Ext, id2Ext );
    }
    if ( $inputOptions.resultExtension === '2' ) {
        toSet.ext = id2Ext;
    }
    if ( $inputOptions.resultExtension === '1' ) {
        toSet.ext = id1Ext;
    }
    if ( $inputOptions.resultExtension === 'none' ) {
        toSet.ext = '';
    }

    var fileFrom = glueExtensionToFileName( fromSet.base, fromSet.ext );
    var fileTo   = glueExtensionToFileName( toSet.base,   toSet.ext   );

    functionCopyFile(
        folderFrom, fileFrom,
        folderTo,   fileTo
    );
}
/*
// test
// can be tested in for browser with only $parser object
$parser.reactionOnGoodParsedBlock(
    'originalA', 'extA',
    'originalB', 'extB',
    {
        direction: 'from-id-2-to-id-1',
        resultExtension: 'auto',
        folderFrom: 'C:\abc',
        folderTo:   'D:\abc'
    },
    function(
        folderFrom, fileFrom,
        folderTo,   fileTo
    ) {
        console.log(
            'folderFrom:', folderFrom,
            'fileFrom:',   fileFrom,
            'folderTo:',   folderTo,
            'fileTo:',     fileTo
        );
    }
);
// expected result:
// folderFrom: C:abc fileFrom: originalA.extA folderTo: D:abc fileTo: originalB.extB
*/






var $copyFileToolbox = {

    copyFileTraining: function(
        folderFrom, fileFrom,
        folderTo,   fileTo
    ) {
        var fso = new ActiveXObject( "Scripting.FileSystemObject" );
        if ( !fso.FolderExists( folderFrom ) ) {
            $b.printErrWarning('folderFrom="' + folderFrom + '" doesn\'t exist');
        }
        if ( !fso.FolderExists( folderTo ) ) {
            $b.printErrWarning('folderTo="' + folderTo + '" doesn\'t exist');
        }

        var pathFrom = fso.BuildPath( folderFrom, fileFrom );
        var pathTo   = fso.BuildPath( folderTo,   fileTo   );

        if ( !fso.FileExists( pathFrom ) ) {
            $b.printErrLine();
            $b.printErrWarning('no source file found, script looking for it at pathFrom="' + pathFrom + '" - this file doesn\'t exist');
        }
        if ( fso.FileExists( pathTo ) ) {
            $b.printErrLine();
            $b.printErrWarning('be advised - there was found a file at destination for copy command, and in "NotTraining" mode you will overwrite file at pathTo="' + pathTo + '"');
        }

        $b.printLine( '' );
        $b.printLine( 'Training mode: you ask to copy file' );
        $b.printLine( 'from: ' + pathFrom );
        $b.printLine( '\/' );
        $b.printLine( 'to:   ' + pathTo );
    },

    copyFile: function(
        folderFrom, fileFrom,
        folderTo,   fileTo
    ) {
        var fso = new ActiveXObject( "Scripting.FileSystemObject" );
        if ( !fso.FolderExists( folderFrom ) ) {
            $b.printErrMessage(' folderFrom="' + folderFrom + '" doesn\'t exist');
            $b.die( basicOptions.errorCodes.badCopy );
        }
        if ( !fso.FolderExists( folderTo ) ) {
            $b.printErrMessage (' folderTo="' + folderTo + '" doesn\'t exist');
            $b.die( basicOptions.errorCodes.badCopy );
        }

        var pathFrom = fso.BuildPath( folderFrom, fileFrom );
        var pathTo   = fso.BuildPath( folderTo,   fileTo   );

        if ( !fso.FileExists( pathFrom ) ) {
            $b.printErrMessage(' no source file found, script looking for it at pathFrom="' + pathFrom + '" doesn\'t exist');
            $b.die( basicOptions.errorCodes.badCopy );
        }

        fso.copyFile( pathFrom, pathTo, true );
    }

}

var $c = $copyFileToolbox;

// you can use it as:
/*
$c.copyFileTraining(
    './', '123.txt',
    'b',  '345.txt'
);
*/
// you will have a lot of problems testing if filename is unicode
// only way that I found for Windows 7 is to pass filename as stdin
// from some file (perhaps any streaming from file works ok here...)
// and yes, test shows that it works...






function main() {

    var $inputOptions = $a.getArgumentsAll();
    $b.printErrLine();
    $b.printErrLine(
        'Arguments for ' + basicOptions.scriptName +
        ' are interpreted this way:'
    );
    $a.print( $inputOptions );
    $b.printErrLine();

    var fCopyFile = $c.copyFileTraining;
    if ( $inputOptions.mode === 'not-training' ) {
        fCopyFile = $c.copyFile;
    }

    /*
    var fuzzy = $fileListToolbox.getAnyFileWithBaseName(
        'input_1',
        $fileListToolbox.getFileListForFolder( 'bTmp' )
    );
    */

    $parser.parseLinesAndForEachBlockDo(
        $s.getLine,
        $parser.reactionOnGoodParsedBlock,
        $inputOptions,
        fCopyFile
    );

    $b.printErr( 'Script ' + basicOptions.scriptName + ' - finished!' );
};

main();