Tuesday, December 16, 2008

Mould / Copy A Directory Tree Structure in Windows

In Windows, it is eay to copy / duplicate the entire directory tree by simply right click the mouse. But, how to mould / copy only the directory tree structure ? This batch file is the answer.

The following batch file named tree_mould.bat can mould / copy the directory tree structure without copying the files inside. It can be used in the command line mode or inside the GUI explorer (by using the Send To).

The batch file will by default mould / copy the directory tree structure to a new directory name with the current date as suffix. So, your PC has to pre-set the short date format as YYYY-MM-DD in order for this batch file proper functioning.

Here is the batch file tree_mould.bat

@echo off
:: ------------------------------------------------------
:: Licence Information:
:: --------------------
:: This coding is offered at no charge for 
:: NON-COMMERCIAL PERSONAL USE only.
:: The coding is copyright.
:: Reproduction of this coding in whole or in part 
:: in any form without the express written permission 
:: of the author is strictly prohibited. 
:: ------------------------------------------------------
:: Disclaimer:
:: -----------
:: This coding is distributed "as is" and is UNSUPPORTED.
:: NO WARRANTY of any kind is expressed or implied.
:: You use AT YOUR OWN RISK.
:: The author will not be liable for any data loss,
:: damages, and loss of profits or any other kind of
:: tangible or intangible loss while using or 
:: misusing this coding.
:: ------------------------------------------------------
:: Name    : tree_mould.bat
:: Purpose : Mould the directory tree using the xcopy command
::           with today as the suffix of the new tree
:: Platform: DOS, Win XP
:: Author  : Alvin SIU
:: Date    : 2007-12-16
:: ------------------------------------------------------
:: Attentions:
:: -----------
:: 1. It is highly recommended to set the SHORT date format
::    of your PC to be YYYY-MM-DD
:: 2. If your short date format uses slash (i.e. /) as 
::    separator, this batch file cannot function properly.
:: ------------------------------------------------------
:: Command Line Usage Example: 
::           tree_mould  A_Directory
:: This will mould the directory tree structure of 
:: A_Directory to A_Directory.d2007-12-16
:: provided that today is 2007-12-16 and the date /t command
:: in your PC will display 2007-12-16
:: ------------------------------------------------------
:: GUI Installation:
::   1. Put this file tree_mould.bat into any directory
::   2. Go to your Send To folder 
::   3. Create a shortcut tree_mould.bat to point to this file
:: GUI Usage Example:
::   1. Highlight any one directory, e.g. A_Directory
::   2. Right click mouse
::   3. Select Send To
::   4. Select the shortcut tree_mould.bat
::   This will mould the directory tree structure of 
::   A_Directory to A_Directory.d2007-12-16
::   provided that today is 2007-12-16 and the date command
::   in your PC will display 2007-12-16
:: ------------------------------------------------------

set TMP_TREE_MOULD_NEW_DIR=%1.d%DATE%

echo tree_mould 
echo from tree : %1 
echo to   tree : %TMP_TREE_MOULD_NEW_DIR%
echo.

if not exist %1 goto NOT_EXIST

if not exist %1\NUL goto NOT_DIR

if exist %TMP_TREE_MOULD_NEW_DIR% goto JUST_EXIST

mkdir %TMP_TREE_MOULD_NEW_DIR%
if errorlevel 1 goto MD_ERR

xcopy /f /t /e %1 %TMP_TREE_MOULD_NEW_DIR%
if errorlevel 1 goto XCOPY_ERR

echo OK, directory tree structure is moulded
goto QUITING

:NOT_EXIST
echo ERROR: There is no such directory %1
goto QUITING

:NOT_DIR
echo ERROR: The item %1
echo ERROR: is NOT a directory
goto QUITING

:JUST_EXIST
echo ERROR: Target directory %TMP_TREE_MOULD_NEW_DIR%
echo ERROR: already exist
goto QUITING

:MD_ERR
echo Error: Cannot Create NEW directory %TMP_TREE_MOULD_NEW_DIR%
goto QUITING

:XCOPY_ERR
echo ERROR: xcopy returns error
goto QUITING

:QUITING
set TMP_TREE_MOULD_NEW_DIR=
echo.
echo.
pause

:: ------------------------------------------------------
:: End Of File tree_mould.bat
:: ------------------------------------------------------

The detail installation and usage instruction are at the beginning of the file.

Alvin SIU
2008-12-16

Copyright/Licence Information:
All information and coding in this article is offered at no charge for NON-COMMERCIAL PERSONAL USE only.
This blog and the coding is copyright.
Reproduction of this blog and its coding in whole or in part in paper or digitally or in any other forms without the explicit written permission of the author is strictly prohibited.

Disclaimer:
All information in this article is distributed "as is" and is UNSUPPORTED.
NO WARRANTY of any kind is expressed or implied.
You use AT YOUR OWN RISK.
The author will not be liable for any data loss, damages, and loss of profits or any other kind of tangible or intangible loss while using or misusing wholly or partly of the information.

Friday, December 5, 2008

What are the Date(s) in a Computer System ?

The term [ Date ] seems to be very simple. Every morning when you wake up, it is a new day with a new date. However, in a computer system, there are many different dates. Here is a brief description of some of the [ dates ].

1. Calendar Date

This is the date related to human being. It is the information got from the paper calendar or from you wrist watch.

2. Business Date

This is also a term related to human being. It refers to those date with business activities.

For many countries, it refers to Monday to Saturday, excluding public holidays. For those 5-day work countries, it refers to Monday to Friday, excluding public holidays.

However, in Israel world, the normal business date is from Sunday to Thursday and Friday morning. So, Sunday is a normal business date.

3. Machine Date / OS Date

This is the date as reported by the operating system (OS) of your machine. In unix or DOS system, this is the information displayed by the [ date ] command. In the MVS mainframe, this is the information usually displayed on the top right part of the ISPF login panel. In Windows, this is the information shown in the clock of the taskbar.

Basically, the file creation/modification/access time is marked with this machine date by the OS.

In unix, normal users are not allowed to change this machine date. The [ date ] command can only display the machine date. But, super users can use the [ date ] command to CHANGE the machine date.

4. Job Order Date

This term applies for some job scheduler. This is the time when the job scheduler to [ create ] a job according to the information in the job database. One can refer it as the job born date. Once a job is ordered out, it comes to this world and is WAITING for execution.

Noted that this job order date may NOT be the same as the job execution date. Usually, a job is executed only when in-condition(s) is satisfied. If there is delay, the job execution date may be 1, 2, 3 or more days after the job order date. In other words, for example, job ordered on 1st of the month may NOT be run/executed on the 1st of the month.

5. Job Execution Date

This is the time when the job starts execution. This is the time when the job is kick-off. If the job creates a job log file once it is run, the file creation date will be the job execution date.

6. System Date

The term [ System Date ] is very ambiguous. It can refer to many things. Some refer system date as the machine date. Some refer this as the [ Today ] of the computer system/project.

When [ System Date ] means the [ Today ] of the computer system/project, usually it will be stored in a file. Then, all the program will read this file to get the [ Today ] value, rather than getting the machine date using API call to the OS. Using this method, all programs will get the SAME date information even when some programs are run after midnight. Also, this method is easy for project/program development and testing. Programmers can put any date you like into the file for development and testing. For example, when testing leap year behavior of your system/project, simply put a Feb 28th or Feb 29th into the file will do.

It is quite odd to use the machine date as the [ Today ] of a computer system/project. When doing so, one has to make sure that all the jobs/programs in the system/project must be finished before midnight. After midnight, it is tomorrow.

7. Reporting Date

Again, [ Reporting Date ] is ambiguous. Some may refer it as the [ Today ] of the computer system/project. Some will refer it as the as-of date of a report generated by the program. Therefore, when using this term, please make sure what is the exact meaning of [ Reporting Date ].

In some computer system/project design, the as-of date of a report is 1 day before the [ Today ] of the computer system/project. This is because that computer system/project is designed to work on data of yesterday. You can view the situation as running the computer system/project after midnight working on data of yesterday.

In some computer system/project design, the as-of date of a report will be the SAME as the [ Today ] of the computer system/project. For example, after 17:00 everyday, all the business data are ready and the jobs of [ Today ] will start working on that data. When the job is running slowly until after midnight to next morning, please ensure that the [ Today ] value will not be changed after midnight.

8. Report Printing Date

This term is clear and non-ambiguous. It simply refers to the time of printing the report.

When reading a report having the text [ Report Date : XXXX-XX-XX ], please make sure what this ambiguous text is talking about. Does it refer to the as-of date ? Or, the report printing date ?

9. File Creation / Modification / Access Date

These 3 types of date information of a file sound simple. For the modification / access date information, they refer to the time of last modified / access of the file. The creation date refer to the time when the file is created.

But, remember that NOT all filesystems will store the file creation date. Many unix inode filesystems does NOT store the file creation date information.

This is a widespread misconception about the [ -ctime ] option of the unix [ find ] command. Actually, the [ c ] does NOT stand for [ creation ]. The [ -ctime ] option shows the last time when the status of the inode is changed. When you change the permission of the file or rename the file, the [ -ctime ] information is updated. In other words, the [ c ] stands for the last [ changed ] time of the inode status of the file. Only when you do not rename, change permission, ... etc on the file since its creation, the ctime can be treated as the file creation date. But this case is really rare.

On the other hand, NTFS5 filesystem will store the file creation date time information. When you copy an old file with a new name, the newly created file will have a modification date OLDER than the file creation date.






After reading this article, next time when designing a computer system/project concerning the [ Date ], please make sure what [ Date ] is talking about. Also, pay additional attention when dealing with the file creation date information.


Wednesday, December 3, 2008

A Trap in SAS Macro Programming

When using SAS macro, beginners will easily fall into this trap if they do not understand that SAS macro is somewhat just a text substitution.

Look at this example. There is a database of 10 persons created using this program :
option mprint source2 noovp ;

data person ;
     length name  $20. ;
     length sex   $1.  ;

     name= 'Angelina'  ; sex= 'F' ; output ;
     name= 'Babara'    ; sex= 'F' ; output ;
     name= 'Clara'     ; sex= 'F' ; output ;
     name= 'Diana'     ; sex= 'F' ; output ;
     name= 'Eva'       ; sex= 'F' ; output ;
     name= 'Frankie'   ; sex= 'M' ; output ;
     name= 'George'    ; sex= 'M' ; output ;
     name= 'Henry'     ; sex= 'M' ; output ;
     name= 'Ivan'      ; sex= 'M' ; output ;
     name= 'John'      ; sex= 'M' ; output ;
run;
After execution, the table person contains these records:
Obs    name        sex

  1    Angelina     F
  2    Babara       F
  3    Clara        F
  4    Diana        F
  5    Eva          F
  6    Frankie      M
  7    George       M
  8    Henry        M
  9    Ivan         M
 10    John         M

Then, three more fields (initial, wear_tie and wear_bra) are added to the table. Records of male and female are with different initialization. The initial is 'Mr.' for all males and 'Miss' for all females. All male records will have wear_tie=Y and wear_bra=N whereas all female records are just the opposite (i.e. wear_tie=N and wear_bra=Y).

For the first thought, here is the program using macro for the initialization :
%macro init_male ;
       initial=  'Mr.' ;
       wear_tie= 'Y'   ;
       wear_bra= 'N'   ;
%mend;

%macro init_female ;
       initial=  'Miss' ;
       wear_tie= 'N'    ;
       wear_bra= 'Y'    ;
%mend;

data person_1 ;
     set person ;
     length initial  $4. 
            wear_tie $1.
            wear_bra $1.     
            ;
     if sex = 'M' then %init_male   ;
     if sex = 'F' then %init_female ;
run;

proc print data=person_1 ;
quit;

The program design seems very straight forward. The macro init_male is for male record initialization and the macro init_female is for all female record initialization.

But, the outcome is not what we expected. Here is the output table person_1 :
Obs    name        sex    initial   wear_tie   wear_bra

  1    Angelina     F      Miss        N          Y
  2    Babara       F      Miss        N          Y
  3    Clara        F      Miss        N          Y
  4    Diana        F      Miss        N          Y
  5    Eva          F      Miss        N          Y
  6    Frankie      M      Mr.         N          Y
  7    George       M      Mr.         N          Y
  8    Henry        M      Mr.         N          Y
  9    Ivan         M      Mr.         N          Y
 10    John         M      Mr.         N          Y
The fields wear_tie and wear_bra are initialized incorrectly for all male records. The male records should have wear_tie=Y and wear_bra=N, but they are not.
How about re-arranging the 2 macro lines like this:
data person_2 ;
     set person ;
     length initial  $4. 
            wear_tie $1.
            wear_bra $1.     
            ;
     if sex = 'F' then %init_female ;
     if sex = 'M' then %init_male   ;
run;

proc print data=person_2 ;
quit;
Now, the output table person_2 looks:
Obs    name        sex    initial   wear_tie   wear_bra

  1    Angelina     F      Miss        Y          N
  2    Babara       F      Miss        Y          N
  3    Clara        F      Miss        Y          N
  4    Diana        F      Miss        Y          N
  5    Eva          F      Miss        Y          N
  6    Frankie      M      Mr.         Y          N
  7    George       M      Mr.         Y          N
  8    Henry        M      Mr.         Y          N
  9    Ivan         M      Mr.         Y          N
 10    John         M      Mr.         Y          N
This time, the result is wrong for all female records.

Actually, both programs have fall into the trap of SAS macro. The correct program should be written like this :
data person_3 ;
     set person ;
     length initial    $4. 
            wear_tie $1.
            wear_bra   $1.     
            ;
     if sex = 'M' then do; %init_male   ; end;
     if sex = 'F' then do; %init_female ; end;
run;

proc print data=person_3 ;
quit;
Then, the table person_3 will have these records :
Obs    name        sex    initial   wear_tie   wear_bra

  1    Angelina     F      Miss        N          Y
  2    Babara       F      Miss        N          Y
  3    Clara        F      Miss        N          Y
  4    Diana        F      Miss        N          Y
  5    Eva          F      Miss        N          Y
  6    Frankie      M      Mr.         Y          N
  7    George       M      Mr.         Y          N
  8    Henry        M      Mr.         Y          N
  9    Ivan         M      Mr.         Y          N
 10    John         M      Mr.         Y          N
The output result is exactly what we want.

Then, actually what is wrong with the programs for person_1 and person_2 ? This is due to SAS macro substitution. SAS will actually [ substitute ] the macro statements into the program. If you do not understand this [ substitution ] activity, you will fall into this trap.

So, for the program fragment for person_1 :
data person_1 ;
     set person ;
     length initial  $4. 
            wear_tie $1.
            wear_bra $1.     
            ;
     if sex = 'M' then %init_male   ;
     if sex = 'F' then %init_female ;
run;
, after substitution, the program fragment will become :
data person_1 ;
     set person ;
     length initial  $4. 
            wear_tie $1.
            wear_bra $1.     
            ;
     if sex = 'M' then initial= 'Mr.' ;
     wear_tie= 'Y' ;
     wear_bra= 'N' ;
     if sex = 'F' then initial= 'Miss' ;
     wear_tie= 'N' ;
     wear_bra= 'Y' ;
run;
(I have re-indent the coding for easy reading. The actual substitution text is quite difficult to read.)

As one can see, after substitution, only the [ initial ] field will work as what we expected. The fields wear_tie and wear_bra will be set regardless of the sex field. At the last 2 lines of the program, all the wear_tie will be N and wear_bra will be Y regardless of male or female record. Thus, the person_1 will have this not-expected output.

However, when calling a macro inside a pair of do-end statements, these 2 lines of coding :
if sex = 'M' then do; %init_male   ; end;
if sex = 'F' then do; %init_female ; end;
, after substitution, will become :
if sex = 'M' then do;
                    initial=  'Mr.' ;
                    wear_tie= 'Y'   ;
                    wear_bra= 'N'   ;
                  end;
if sex = 'F' then do;
                    initial=  'Miss' ;
                    wear_tie= 'N'    ;
                    wear_bra= 'Y'    ;
                  end;
(Again, I have re-indent the coding for easy reading.)

This is what we expected.

To avoid falling into this trap, always remember that SAS macro can be treated as text substitution.


Alvin SIU
2008-12-03
Copyright/Licence Information:
All information and coding in this article is offered at no charge for NON-COMMERCIAL PERSONAL USE only.
This blog and the coding is copyright.
Reproduction of this blog and its coding in whole or in part in paper or digitally or in any other forms without the explicit written permission of the author is strictly prohibited.

Disclaimer:
All information in this article is distributed "as is" and is UNSUPPORTED.
NO WARRANTY of any kind is expressed or implied.
You use AT YOUR OWN RISK.
The author will not be liable for any data loss, damages, and loss of profits or any other kind of tangible or intangible loss while using or misusing wholly or partly of the information.

Duplicate Open Current Folder in a New Window

Sometimes after I opened a folder in Win7, I would like to duplicate open the same folder again in another explorer window. Then, I can ope...