@echo off
if %1!==}{! goto pass2
if exist }{.dat del }{.dat
set rand=
for %%a in (! ! ! ! ! ! ! !) do call %0 }{
gawk "BEGIN{srand();printf(\"set rand=\045rand\045\")}{printf(\"\045c\",65+int(26 * rand()))}END{print\"\"}" }{.dat > }{.bat
call }{
:done
REM your code to use the string goes here
echo %rand%
del }{.?at
set rand=
goto end
:pass2
echo. >> }{.dat
goto end
:end
{
sub( / $/, "" )
Array[ $0 ] = ""
}
END{
srand()
flag = 0
while( !flag ){
string = ""
for( i = 0; i < 8; ) {
number = 48 + (42 * rand())
if( (number < 58) || ( number > 64) ) {
string = string sprintf( "%c", number )
i++
}
}
flag = 1
if( string in Array ) flag = 0
}
print "set string=" string
}
The program first reads the file into an array, then uses the pseudorandom number generator to select characters. While the variable is still a number, it is tested for range to reject the punctuation characters that occur between the numerals and the upper case letters. If the number is in one of the proper ranges, it is converted to a character and appended to the string in work until the limit of eight is reached, at which time the program prints the SET command to STDOUT.
@echo off
gawk -fmakerand.awk strings.dat > }{.bat
call }{
del }{
echo %string% >> strings.dat
There is one thing not mentioned so far - the very first line in the script strips trailing spaces from the input - that is to accomodate the space between the '%' and ">>" in the last line of the batch file. The space is there to make the program NT compatible (if the string has a trailing '1' or '2', NT would interpret it as part of the redirection , not as part of the string).
BEGIN{
W9xFlag = 1
if( "SIZEFIELD" in ENVIRON ) W9xFlag = 0
ClusterSize = ENVIRON["CLUSTERSIZE"]
DirSize = ENVIRON["DIRSIZE"]
SizeField = ENVIRON["SIZEFIELD"]
DriveSize = ENVIRON["DRIVESIZE"]
}
{
if( $0 != "" ){
if( $0 ~ /<DIR>/ ) {
# If the line is a directory entry
DotFlag = 0
for( i = 1; i <= NF; i++ ) {
if( $i == "." ) DotFlag = 1
if( $i == ".." ) DotFlag = 1
}
# If the line is a directory but not . or ..
if( !DotFlag ) TotalClusters += DirSize
}
else {
if( $0 !~ /^ / ){
# If the line does not begin with a space and is not a directory entry, it is a file entry
if( W9xFlag ) {
for( i = 1; i <= NF; i++ ) {
if( $i ~ /:/ ) {
SizeField = i - 2
}
}
}
# Remove the commas
gsub( /,/, "", $SizeField )
Clusters = int( $SizeField / ClusterSize )
# If there is a remainder, we have to increment the cluster count to account for the one partially used
if( $SizeField % ClusterSize ) Clusters++
TotalClusters += Clusters
}
}
}
}
END{
print "Total Clusters Needed = " TotalClusters, "DriveSize = " DriveSize " bytes"
ExitCode = 0
if( ( ClusterSize * TotalClusters ) > DriveSize ) ExitCode = 1
exit( ExitCode )
}
(This was written for Netscape 4.6 which incorrectly handles <DIR> inside the PRE/CODE block. I had to change the < and > characters to their escaped equivalents "<" and ">" - if it comes out wrong, just read it as if it were correct - if you copy/paste the code, make sure it looks like the DIR marker in a directory listing in your script.)dir | awk -ffoo.awk
where foo is the name you gave the file (use .AWK as the extension). Don't forget to set the environment variables to their proper values.{
if( $0 ~ /bytes free/){
gsub( /,/, "", $(NF-2) )
print "set DRIVESIZE=" $(NF-2)
}
}
Here's a batch program that just sets the DRIVESIZE variable to the size (in bytes) of drive d: (a Zip drive in my case). @echo off
echo {if( $0 ~ /bytes free/){ > }{.awk
echo gsub( /,/, "", $(NF-2) ) >> }{.awk
echo print "set DRIVESIZE=" $(NF-2)}} >> }{.awk
dir d: | awk -f}{.awk > }{.bat
call }{.bat
del }{.*
I recommend that users copy/paste both scripts as given into the files WILLFIT.AWK and TARGETSZ.AWK, and use this batch program after changing the constants to whatever is appropriate for the target drive.@echo off
set CLUSTERSIZE=2048
set DIRSIZE=1
set sizefield=
dir i: | awk -ftargetsz.awk > }{.bat
call }{.bat
del }{.bat
dir c:\*.* /s | awk -fwillfit.awk
if errorlevel 1 goto fail
xcopy c:\*.* d:\ /s
goto end
:fail
echo Not enough room
:end
> @echo off
awk "{print \"set count=\" ++$0}" foo > }{.bat
for %%a in (call del) do %%a }{.bat
md g:\a\Logs_%count%
echo %count% > foo
That's a throw-away - the code is not reused here.# DISKSIZE filters the output of a CHKDSK command to
# extract the size of the allocation units on the disk and the number
# of allocation units available.
# These numbers are inserted into a string given in the
# DSKSZPAT environemnt variable in place of markers placed in that string.
# The markers are ::size::, ::number::, and ::total::. The pattern string can
# contain any plain text and the markers \t and \n for Tab and newline.
# \e, \l, \r, and \p can be used to represent "=", "<", ">", and "|" symbols,
# and \a and \h to represent & and ^. If the markers are needed as strings
# literal, use a double backslash (\\t to get \t, for example).
# Upper case versions of the markers will result in any thousands separators
# that are present in the numbers being retained in the output - lower
# case versions will result in removal of the separators.
# The output of the CHKDSK comand normally will be piped to this program
# and the output of this filter will be redirected into a file.
# Typical usage would be to generate a batch file to set environment variables
# to the two numbers, so that is the default pattern to be used if the user
# does not provide one. If only a screen readout is wanted, a pattern
# string of "Unit size = :: size::\t Number of units = ::number::" would
# generate a single line response with a bit of space between the two reports.
# Note that size is in bytes, and number is the count of units of the given
# size available on the disk - *not* the total number of units on the disk;
# that is obtained with the total marker.
# If total number is needed, a blank disk must be used
BEGIN{
# Define the pattern for the output format - if a user defiend pattern is
# available, use it instead of the default.
OutputFormat = ENVIRON[ "DSKSZPAT" ]
if( OutputFormat == "" )
OutputFormat = "set DSKSZSIZE=::size::\nset DSKSZNUM=::number::"
# Replace any instances of the Tab and newline markers, and the special
# symbol markers with the real ones -
OutputFormat = ReplaceSymbols( OutputFormat )
# Initialize the output variables to nulls in case the input is not a
# valid CHKDSK output with the expected format. ("AU" stands for "Allocation
# Unit".)
AUsize = ""
AUnumber = ""
AUtotal = ""
AUsizeRaw = ""
AUnumberRaw = ""
AUtotalRaw = ""
}
# Process the input lines.
{
# The line with the allocation unit size is a bunch of space, a number, then
# the string "bytes in each allocation unit.". We will use "each alloc" as
# the recognition pattern for that line. The number is the first field found
# by the automatic line parser.
if( $0 ~ /each alloc/ ) AUsizeRaw = $1
# The line with the number of available units is a bunch of space, a number,
# then the string "allocation units available on disk". We will use "units
# avai" as the recognition pattern for that line. The number is the first
# field found by the automatic line parser.
if( $0 ~ /units avai/ ) AUnumberRaw = $1
# The line with the total number of units is a bunch of space, a number,
# then the string "total allocation units on disk". We will use "total
# alloc" as the recognition pattern for that line. The number is the first
# field found by the automatic line parser.
if( $0 ~ /total alloc/ ) AUtotalRaw = $1
}
END{
# Make copies of the raw numbers for thousands separator removal.
AUsize = AUsizeRaw
AUnumber = AUnumberRaw
AUtotal = AUtotalRaw
# Remove the thousands separators, is any are present - anything except
# numbers is treated as a separator. This is done ahead of the test for
# sanity to catch any errors from matched lines in wrong input that don't
# have numbers in the proper places.
gsub( /[^0-9]/, "", AUsize )
gsub( /[^0-9]/, "", AUnumber )
gsub( /[^0-9]/, "", AUtotal )
# Write the results to STDOUT unless the input was defective and the values
# weren't found or the values aren't numbers.
if( (AUsize != "") && (AUnumber != "") && ( AUtotal != "") ) {
# Make the substitutions.
gsub( /::size::/, AUsize, OutputFormat )
gsub( /::number::/, AUnumber, OutputFormat )
gsub( /::total::/, AUtotal, OutputFormat )
gsub( /::SIZE::/, AUsizeRaw, OutputFormat )
gsub( /::NUMBER::/, AUnumberRaw, OutputFormat )
gsub( /::TOTAL::/, AUtotalRaw, OutputFormat )
# Print the modified string.
print OutputFormat
}
else {
# Print an error message if the numbers weren't sane. It would be nice if
# we could force this to STDERR, but the standard method for that doesn't
# exist in the Microsoft world. We can return an ERRORLEVEL (exit code).
print "ERROR: invalid input format."
exit( 1 )
}
exit( 0 )
}
function ReplaceSymbols( String ) {
# Replace symbols for newline, Tab, and certain characters that are magic in
# various batch languages with the real characters.
# In order to provide a method of inserting these symbols as literals,
# provision must be made to escape the backslash - this is done by
# doubling the \ to \\, so a literal \t is represented by \\t.
# The way to deal with that is to replace \\ with something else before
# processing the symbols, then replace the something else with \. ^Z is
# used because it cannot appear in the controlling batch files.
gsub( /\\\\/, "\032", String )
gsub( /\\t/, "\t", String )
gsub( /\\n/, "\n", String )
gsub( /\\e/, "=", String )
gsub( /\\l/, "<", String )
gsub( /\\r/, ">", String )
gsub( /\\p/, "|", String )
gsub( /\\h/, "^", String )
# According to all available documentation this next line is incorrect:
# \\& is supposed to be \&. Just as inserting a $ would require \$ -
# *that* works, but not \& to insert &. This may be version sensitive,
# but it works with the four versions available to me.
gsub( /\\a/, "\\&", String )
# Now fix the backslashes by replacing ^Z with \.
gsub( /\032/, "\\", String )
return( String )
}
That also contains characters that are magic in NT, so there would be problems getting it into a file under that OS anyway. This script is use in conjunction with CHKDSK to generate most any kind of output report you need: to the screen, a batch file, a delimited list (with or without quoting) for a spread sheet - most anything. See the section on DLIST for a discusssion of formats for this type of program - I reused the formatting concept unchanged except for the details of its implementation. This batch file takes a drive letter and colon as its argument and puts the size of the disk's allocation units and the number of available allocation units in the environment after removing any thousands separators that might be present in the reported numbers (NT doesn't use them, the other MS operating systems do).
@echo off
chkdsk %1 | awk -fdisksize.awk > }{.bat
for %%a in ( call del ) do %%a }{.bat
The main part of the program is a script to read a directory listing and generate a batch file that will create any needed directory entries in the target directory and copy as many files as will fit within the size limit set for the target.BEGIN{
# Define a global exit code variable - this is used as a flag and a value.
ExitCode = 0
# Read the environment variables into global variables for this program.
SourceRoot = ENVIRON[ "DSIZEROOTS" ]
TargetRoot = ENVIRON[ "DSIZEROOTT" ]
ErrorFile = ENVIRON[ "DSIZEERR" ]
Format = ENVIRON[ "DSIZEFORMAT" ]
LastLine = ENVIRON[ "DSIZELASTF" ]
DirNumber = ENVIRON[ "DSIZENUM" ]
MaxAUs = ENVIRON[ "DSIZEAUNUM" ]
AUsize = ENVIRON[ "DSIZEAUSIZE" ]
DirSize = ENVIRON[ "DSIZEDIRSIZE" ]
Header = ENVIRON[ "DSIZEHEAD" ]
MDformat = ENVIRON[ "DSIZEMDF" ]
# Some of those must be initialized to default values if they are blank
# The default error file:
if( ErrorFile == "" ) ErrorFile = "dsizeerr.txt"
# and the directory number:
if( DirNumber == "" ) DirNumber = 1
# The string used to create new directories must exist or receive a default
# string, and also have the special symbols replaced.
if( MDformat == "" ) MDformat = "MD ::dir::"
MDformat = ReplaceSymbols( MDformat )
# SourceRoot must be initialized, but that is done at the first input line
# if it wasn't given in the environment.
# For effeciency (numerical comparisons are faster than string comparisons),
# a flag will be used to mark whether it has been initialized or not. This
# is the only time a string comparison will be used for that purpose.
SourceRootFlag = 0
if( SourceRoot != "" ) SourceRootFlag = 1
# If there is no trailing backslash, add one.
if( SourceRoot !~ /\\$/ ) SourceRoot = SourceRoot "\\"
# DirSize defaults to one AU or 16Kb, whichever is greater.
Temp = 1024 * 16
if( AUsize > Temp ) Temp /= AUsize
if( DirSize == "" ) Dirsize = Temp
# If TargetRoot is null, the program must abort.
if( TargetRoot == "" ) {
print "ERROR: DSIZEROOTT environment variable missing." > ErrorFile
# The program normally exits with an exit code (ERRORLEVEL) of 0, but if
# it abortes, it exits with a non-zero value, 1 in this case.
ExitCode += 1
}
# If the size of the target or the size of the target's AU is missing, it is
# necessary to abort.
if( MaxAUs == "" ) {
print "ERROR: DSIZEAUNUM environment variable missing."
ExitCode += 2
}
if( AUsize == "" ) {
print "ERROR: DSIZEAUSIZE environment variable missing."
ExitCode += 4
}
# Note that the exit codes are powers of two - multiple errors can be
# determined from its final value.
if( ExitCode ) exit( ExitCode )
# An exit command does not terminate the program in standard AWK versions,
# the END code will still run.
# Both output pattern strings need to have the \n amd \t markers replaced
# with the real things, and also the markers for =, <, >, and |.
# \e, \l, \r, and \p can be used to represent "=", "<", ">", and "|" symbols,
# and \a and \h to represent & and ^. If the markers are needed as strings
# literal, use a double backslash (\\t to get \t, for example).
Format = ReplaceSymbols( Format )
LastLine = ReplaceSymbols( LastLine )
# Print the header, if there is one. Since no data have been processed
# it makes little sense to have replacable parameters here (other than
# the special symbols - it's just a string litteral.
# It is expected that it will usually be "@echo off".
print ReplaceSymbols( Header )
# Set the field separator to a single comma so that the comma delimited
# input lines will be properly parsed into fields.
FS = ","
# A Global variable is needed for the accumulating file sizes.
TotalAUs = 0
# The actual target directory is the TargetRoot directory with DirNumber
# appended. If the number has one or more leading zeros, the number will
# be left padded with leading zeros to the same total length if need be.
DirNumberLength = 0
if( DirNumber "" ~ /^0/ ) DirNumberLength = length( DirNumber "" )
# The "" forces it to be treated as a string.
# TargetRoot must not have a trailing backslash - it's not a complete
# directory spec.
sub( /\\$/, "", TargetRoot )
# Now build the complete directory substitution string from the pieces
# and write a command to create it.
DirString = NewDirectory( TargetRoot, DirNumber, DirNumberLength )
# Correct total to account for estimated size of the directory.
TotalAUs += DirSize
}
# Each line is in the format: directory, full long name filespec, size.
# There are no spaces except those in file and directory specs.
{
# Test for and abort any blank lines
if( $0 == "" ) next
# Test for whether SourceRoot is set. If we could be certain that the first
# record would not be blank, we could just use NR.
if( !SourceRootFlag ) {
SourceRoot = $1
SourceRootFlag++
}
# $1 is required to have a trailing backslash because the input file is in
# DLIST format, so SourceRoot does not need processing to add one.
# We have to double the backslashes in SourceRoot so it can be used as a
# pattern later. We need to do this exactly once.
if( SourceRootFlag == 1 ) {
gsub( /\\/, "\\\\", SourceRoot )
SourceRootFlag ++
}
# Size computation - $3 is the size in bytes.
# First test to see if the file is larger than the target can ever hold.
FileAUs = $3 / AUsize
if( FileAUs > MaxAUs ) {
print "ERROR: " $2 " is too large." > ErrorFile
next # Done with this line, read and process the next one.
}
# Fall through to here means the file is not larger than the target space.
# The next question is will it fit in the current directory.
TotalAUs += FileAUs
if( TotalAUs > MaxAUs ) {
# If it will not fit, start a new directory,
DirString = NewDirectory( TargetRoot, ++DirNumber, DirNumberLength )
# Reset the total counter to 0
TotalAUs = 0
}
# We now have a string containing the fully qualified filespec of the
# file in work, the name of the target directory it is to go in, and
# knowledge that the directory will exist and that the file will fit.
# The user has provided a command string that is to move or copy the
# file. Note that if the file is in a subdirectory of the source root,
# it will be in the same subdirectory under the target root. There are
# only two substitutions that need be made: the old filespec and the new.
# The third substitution is included for completeness.
# The new is the old with the root replaced with the target root. The
# original filespec is the second field in the input line.
Filespec = $2
OutString = Format
sub( SourceRoot, DirString, Filespec )
gsub( /::old::/, $2, OutString )
gsub( /::new::/, Filespec, OutString )
gsub( /::number::/, DirNumber, OutString )
print OutString
}
END {
# If the program is in abort mode, it is necessary to skip the code here.
if( !ExitCode ) {
# The only substitution that makes any sense in LastLine is the number
# of the next directory to create, but the other two are included just in
# case someone needs them - after all, both output strings can be multiple
# lines.
DirNumber = PadDirNumber( ++DirNumber, DirNumberLength )
gsub( /::number::/, DirNumber, LastLine )
print LastLine
}
}
function PadDirNumber( Number, TotalLength ) {
# Obviously, if TotalLength is zero (no padding), the while loop will
# not change the number string at all.
while( length( Number "" ) < TotalLength ) {
Number = "0" Number ""
}
return( Number )
}
function ReplaceSymbols( String ) {
gsub( /\\t/, "\t", String )
gsub( /\\n/, "\n", String )
gsub( /\\e/, "=", String )
gsub( /\\l/, "<", String )
gsub( /\\r/, ">", String )
gsub( /\\p/, "|", String )
return( String )
}
function NewDirectory( Base, Number, Length, DirString, String ) {
DirString = Base PadDirNumber( DirNumber, Length )
# That line increments the directory number counter, pads it with leading
# zeros, and rebuilds the string that replaces the invarient part of the
# source filespec. This string is substituted into MDformat and the result
# printed as the command to create a new directory. We have to work on a
# copy of MDformat because we may have to repeat the substitutions later.
String = MDformat
gsub( /::dir::/, DirString, String )
print String
# Add a trailing backslash when returning the directory string.
return( DirString "\\")
}
This script - and the DLIST.AWK script (below) which is a preprocessor for this script - would be managed with a batch file somewhat like this one (the example is NT specific): @echo off
set DLISTNOH=foo
set DLISTL=::dir::,::dir::::long::,::SIZE::
set DSKSZPAT=set DSIZEAUNUM\e::number::\nset DSIZEAUSIZE\e::size::
set DSIZEROOTT=d:\foo
set DSIZEFORMAT=move ::old:: ::new::
set DSIZENUM=001
set DSIZEMDF=if not exist ::dir:: md ::dir::
set DSIZEHEAD=@echo off
if exist dsizenbr.bat call dsizenbr
set DSIZELASTF=echo set DSIZENUM=::number:: \r dsizenbr.bat
chkdsk %1 | awk -fdisksize.awk > }{.bat
for %%a in ( call del ) do %%a }{.bat
dir c:\myfiles\*.* /s | awk -fdlist.awk | awk -fdirsize.awk > }{.bat
REM for %%a in ( call del ) do %%a }{.bat
Don't uncomment that last line until you are absolutely sure that }{.bat is being properly generated. It won't actually run, or be erased, until the REM is removed. Check it carefully before turning the program loose on your files. This is presented as example code only, and if you use it, you are on your own as far as responsibility goes - there are entirely too many variables for me to write code that is certain to work properly on your machine in your environment with the version of AWK you are using without me being there to test it.
BEGIN{
Dflag = 0
}
{
echo
if( !Dflag ) {
Dflag = 1
ThisDate = $NF
gsub( /[^0-9]/, "+", ThisDate )
Fields = split( ThisDate, Array, "+" )
ThisDate = Array[ Fields ] Array[ Fields - 2 ] Array[ Fields -1 ]
print "@set DDATE=" ThisDate
}
}
That script doesn't contain any magic characters (except one '^' which is magic in NT), so it can be created on the fly by this batch program which writes a script which writes a batch program: @echo off
echo BEGIN{ Dflag = 0 }> }{.awk
echo {if(!Dflag){Dflag=1;ThisDate=$NF >>}{.awk
if %OS%!==Windows_NT! echo gsub(/[^^0-9]/," ",ThisDate)>> }{.awk
if not %OS%!==Windows_NT! echo gsub(/[^0-9]/," ",ThisDate)>> }{.awk
echo Fields=split(ThisDate,Array," ")>> }{.awk
echo ThisDate=Array[ Fields ]Array[(Fields-2)]Array[(Fields-1)]>> }{.awk
echo print"@set DDATE="ThisDate}}>> }{.awk
echo. | date | awk -f}{.awk > }{.bat
call }{.bat
echo %DDATE%
del }{.*
Note that I have removed all unnecessary spaces and newlines from the script. It could be all one line - or maybe two - but there are line length limits here and in the batch program. Note also that separate lines with IF test of the OS environment variable are used to provide a line with '^' escaped ("^^") if the OS is NT and in plain form if it is not (the OS variable doesn't exist except in NT, so its value is an empty string in the other environments).BEGIN{
# Initialize some variables that may not otherwise receive an initial value.
HeaderFlag = 0
FooterFlag = 0
Footer[1] = ""
Footer[2] = ""
LineFlag = 0
# If DLISTNOH even exists in the environment, we need to inhibit header code.
# This can be accomplished by setting the header flag to a special value.
if( ENVIRON["DLISTNOH"] != "" ) HeaderFlag = 3
# Read the other environment variables into variables with easier names and
# assign default values to those that don't exist.
ListFormat = ENVIRON[ "DLISTL" ]
if( ListFormat == "" ) ListFormat = "::dir::::long::\t ::date::\t ::time::\t ::size::"
# Replace any litteral \t and \n marks with their real values. Also the magic
# characters for various operating systems: = for \e, < for \l, > for \r,
# | for \p, ^ for \h, and & for \a.
ListFormat = ReplaceSymbols( ListFormat )
}
{
# Extract the first header encountered (or none if the header is inhibited).
# There are two lines in the header, so starting with a count of 0 and
# incrementing twice will pass just the first two lines from the first
# header encountered. Note that this may be language version sensitive.
# The ordering of the tests combined with the "next" statement prevents
# processing of these header lines as listing lines.
if( $1 ~ /Volume/ ) {
if( HeaderFlag < 2 ) {
if( $0 !~ /:/ ) {
HeaderFlag++
# Print the lines as encountered and get it over with. (This also facilitates
# testing the code as it is written.)
print $0
}
}
next
}
# For each directory in the listing, we need the name of the directory.
# The directory name is in the line in its listing's header that begins
# "Directory of " and consists of the rest of the line.
if( $0 ~ /Directory of/ ) {
ThisDir = $0
# We all know there are no bugs in MS software, so this must be a feature:
# if the /s switch is present in Win95 (and possibly other versions),
# there is no leading space on the line containing the directory listing.
# The substitution regex must have " ?" to test for zero or one space.
sub( / ?Directory of /, "", ThisDir )
Array[ "::dir::" ] = ThisDir "\\"
# If HeaderFlag equals exactly 2, the header is done and the footer is
# allowed - look for it. The footer lines are the last two lines having
# a number followed by exactly one space followed by the string "bytes".
# This definition is valid for all the recent MS operating systems. Since
# not every occurence of a string that matches this is the real thing, it
# is necessary to reset FooterFlag after each occurence that isn't. This
# is done by detecting a directory listing line from the presence of an
# "a" or "p" which exists in all time stamps, but not in the footer lines.
if( HeaderFlag == 2 ) {
if( $0 ~ /[ap]/ ) FooterFlag = 0
if( $0 ~ /[0-9] bytes/ ) Footer[ ++FooterFlag ] = $0
}
# It would be possible to save a bit of code by rearranging the above
# to put the test for [ap] first and putting the following code in the
# else block, but it would not be as clear as separately testing for
# DIR listing lines - the test is repeated here in the opposite sense:
# if the line has a date stamp, it is to be processed.
# Clean up reusable variables - most are elements in an array.
Array[ "::long::" ] = ""
Array[ "::short::" ] = ""
Array[ "::date::" ] = ""
Array[ "::time::" ] = ""
Array[ "::size::" ] = ""
Extention = ""
# A "next" statement here prevents processing of this line as a listing line.
next
}
# Note that the substitution pattern includes the spaces around the pattern -
# this code is highly language version sensitive, but easily modified.
# Now for the listing lines.
# The following code will not assume that the DIR command contained a /a:-d
# switch to suppress directory listings. Directory lines contain
# are ignored.
if( $0 ~ /[ap]/ ) if( $0 !~ // ) {
# Find the time stamp: if it is in field 2, the OS is NT. The time stamp
# has a colon followed by a two digit number between 00 and 59 and either
# "a" or "p".
if( $2 ~ /:[0-5][0-9][ap]/ ) {
Array[ "::date::" ] = $1
Array[ "::time::" ] = $2
Array[ "::size::" ] = $3
# The only major restriction on NT DIR formatting is that the /x switch
# is not allowed - it's just too difficult to deal with. The long name
# begins with column 40.
Array[ "::long::" ] = substr( $0, 40 )
}
else {
# If it isn't NT, then it's one of the DOS/Win9x formats.
# $1 is the short name base,
# if $5 contains a : followed by 00-59 and an "a" or 'p"
# $2 is the extension
# $3 is the size
# $4 is the date
# $5 is the time
# else
# $2 is the size
# $3 is the date
# $4 is the time
# and there is no extension
# anything beyond the date field is the long name.
T = $1
if( $5 ~ /:[0-5][0-9][ap]$/ ) {
d = $5
Array[ "::short::" ] = T "." $2
Array[ "::size::" ] = $3
Array[ "::date::" ] = $4
}
else {
d = $4
Array[ "::short::" ] = T
Array[ "::size::" ] = $2
Array[ "::date::" ] = $3
}
Array[ "::time::" ] = d
i = index( $0, d ) + length( d ) + 1
if( length( $0 ) > i ) {
Array[ "::lomg::" ] = substr( $0, i )
}
}
# If the short name is null after removing its spaces, there wasn't one,
# and the long name and short name are the same - force the short name
# to the only name.
gsub( / /, "", Array[ "::short::" ] )
if( Array[ "::short::" ] == "" ) Array[ "::short::" ] = Array[ "::long::" ]
# Similarly, if the long name is null, then force it to the short name value.
# They can't both be null in the listing.
if( Array[ "::long::" ] == "" ) Array[ "::long::" ] = Array[ "::short::" ]
# Make a copy of the size field without delimiters - anything not a number
# is a delimiter.
OutString = ListFormat
t = Array[ "::size::" ]
gsub( /[^0-9]/, "", t )
Array[ "::SIZE::" ] = t
for( i in Array ) {
t = Array[ i ]
gsub( i, t, OutString )
}
print OutString
}
}
END{
# Print the footer if there is one. (This part was written at the same time
# as the footer code to facilitate testing as code was written.)
if( FooterFlag ) for( i in Footer ) print Footer[ i ]
}
function ReplaceSymbols( String ) {
# Replace symbols for newline, Tab, and certain characters that are magic in
# various batch languages with the real characters.
# In order to provide a method of inserting these symbols as literals,
# provision must be made to escape the backslash - this is done by
# doubling the \ to \\, so a literal \t is represented by \\t.
# The way to deal with that is to replace \\ with something else before
# processing the symbols, then replace the something else with \. ^Z is
# used because it cannot appear in the controlling batch files.
gsub( /\\\\/, "\032", String )
gsub( /\\t/, "\t", String )
gsub( /\\n/, "\n", String )
gsub( /\\e/, "=", String )
gsub( /\\l/, "<", String )
gsub( /\\r/, ">", String )
gsub( /\\p/, "|", String )
gsub( /\\h/, "^", String )
# According to all available documentation this next line is incorrect:
# \\& is supposed to be \&. Just as inserting a $ would require \$ -
# *that* works, but not \& to insert &. This may be version sensitive,
# but it works with the four versions available to me.
gsub( /\\a/, "\\&", String )
# Now fix the backslashes by replacing ^Z with \.
gsub( /\032/, "\\", String )
return( String )
}
Since that script is so long and complex, it isn't practical to generate it on the fly - it should be saved as a utility script and invoked with a batch file like this one - this is not a working program: you have to insert some user and use specific data
@echo off
set DLIST=pattern
cd foo
dir %1 | gawk -fdlist.awk > dlist.txt
where foo is the directory containing the script and to contain the output file and pattern is the output format string.
*************** More later ************
** Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001 Ted Davis - see License, included by reference. **
Input and feedback from readers are welcome. NOTE: the subject of the message must contain the word "batch" for the message to get past the spam filter.
Back to the Table of Contents page
Back to my personal links page - back to my home page