A long time ago (the dinosaurs had only just become extinct) I administered a 1Mbps 30 user 10Net network which was connected to a SUN model 3/60 workstation (or was it just 360?) for internet e-mail.
Since I sometimes had to make backups, I thought I might just as well study some of Unix' command line utilities.
At that time I didn't like the complex syntax of these utilities at all, so I soon stopped studying.
There were 3 utilities I did like, though, and found very useful indeed: CUT, TEE and WHICH.
That's why I "ported" them, first to (OS/2) Rexx, and later to NT and DOS batch and Perl, and more recently to KiXtart, PowerShell and VBScript too (WHICH only).
The Rexx and batch sources of these ports can be found here:
#! perl $syntax = "\nCut.pl, Version 1.11\nPort of Unix' CUT command\n\n"; $syntax = $syntax."Usage:\n\nany_cmd | PERL CUT.PL [-DEBUG] "; $syntax = $syntax."{-C:n|-F:n [-D:'any_string' [-I]]} [-L:n] [-S]\n\n"; $syntax = $syntax."Argument: Function:"; $syntax = $syntax." Dependency:\n"; $syntax = $syntax."========= ========="; $syntax = $syntax." ===========\n"; $syntax = $syntax."any_cmd command that's output is to be parsed"; $syntax = $syntax."\n-DEBUG display intermediate results\n"; $syntax = $syntax." (preferably the first argument)\n"; $syntax = $syntax."-C:<column_number> parse by Columns or Characters\n"; $syntax = $syntax."-D:'<delimiter>' Delimiter character or string"; $syntax = $syntax." -F\n"; $syntax = $syntax." (should be escaped if necessary)\n"; $syntax = $syntax."-F:<field_number> parse by Fields or words\n"; $syntax = $syntax."-I case Insensitive delimiter"; $syntax = $syntax." -D\n"; $syntax = $syntax."-L:<length> number of characters or words "; $syntax = $syntax."to display -C\n"; $syntax = $syntax."-S Skip blank lines in result\n\n"; $syntax = $syntax."Written by Rob van der Woude\n"; $syntax = $syntax."http://www.robvanderwoude.com\n"; # Assign default values $case = 1; $debug = 0; $delim = "\\s"; $help = 0; $len = 0; $skip = 0; # Command line parsing is SO much easier using regular expressions foreach $_ ( @ARGV ) { if ( $debug == 1 ) { print "$_\n"; } SWITCH: { if ( $_ =~ m/^-C:(\d+)$/i ) { $type = "char"; $char = $1; last SWITCH; } if ( $_ =~ m/^-D:\'?([^.']+)\'?$/i ) { $delim = $1; last SWITCH; } if ( $_ =~ m/^-DEBUG$/i ) { $debug = 1; print "\nCommand line arguments:\n$_\n"; last SWITCH; } if ( $_ =~ m/^-F:(\d+)$/i ) { $type = "word"; $word = $1; last SWITCH; } if ( $_ =~ m/^-I$/i ) { $case = 0; last SWITCH; } if ( $_ =~ m/^-L:(\d+)$/i ) { $len = $1; last SWITCH; } if ( $_ =~ m/^-S$/i ) { $skip = 1; last SWITCH; } $help = 1; } } if ( !@ARGV[0] or ( $help == 1 ) ) { print $syntax; exit(1); } # Debug info if ( $debug == 1 ) { print "\nInterpretation of command line arguments:\n"; print "\$case=$case\n\$char=$char\n\$delim=$delim\n"; print "\$len=$len\n\$skip=$skip\n\$type=$type\n\$word=$word\n"; } # Create the regular expressions to parse ("cut") the string $re = "^"; if ( $type eq "word" ) { if ( $case == 0 ) { $re = $re."^(?i)"; } $re = $re."(?:$delim)*"; if ( $word > 1 ) { for ( $i = 1; $i < $word; $i++ ) { $re = $re."[^$delim]+(?:$delim)+"; } } $re = $re."("; $re0 = $re.".*)\$"; if ( $len > 0 ) { $re = $re."[^$delim]+"; for ( $i = 1; $i < $len; $i++ ) { $re = $re."(?:$delim)+[^$delim]+"; } $re = $re.")(?:$delim)"; } else { $re = $re0; } if ( $case == 0 ) { $re = $re."(?-i)"; } } else { # if ( $type eq "char" ) { if ( $char > 0 ) { $re = $re.".{".( $char - 1 )."}"; $re0 = $re."(.*)\$"; } if ( $len > 0 ) { $re = $re."(.{0,$len})"; } else { $re = $re0; } } # Debug info if ( $debug == 1 ) { print "\nRegular Expression:\n$re\n"; print "\nStandard input \& \"cut\" result:\n"; } # Parse STDIN and display results while ( <STDIN> ) { chomp $_; if ( $debug == 1 ) { print "STDIN: $_\n"; } $m = $_; if ( $_ =~ $re ) { print "$1\n"; } elsif ( $_ =~ $re0 ) { print "$1\n"; } elsif ( $skip == 0 ) { print "\n"; } }
/* * * * * * * * * * * * * * * * * * * * * * * * * */ /* Attempt to "port" the Unix CUT command to Rexx */ /* Rob van der Woude, May 16 1998 - June 4 2000 */ /* Usage: any_command | CUT { -C:n | -F:n */ /* [ -D:"any_string" [ -I ] ] } [ -L:n ] */ /* [ -S ] [ -V:varname ] [ -X:command ] */ /* * * * * * * * * * * * * * * * * * * * * * * * * */ /* Load RexxUtil */ if RxFuncQuery( "SysLoadFuncs" ) <> 0 then do call RxFuncAdd "SysLoadFuncs", "RexxUtil", "SysLoadFuncs" call SysLoadFuncs end /* Parse and check command line */ parse arg cmdline cmdline = translate( cmdline, '-', '/' ) parse value cmdline with cmdline'-x:'xcommand if xcommand = "" then parse value cmdline with cmdline'-X:'xcommand cmdline = strip( cmdline ) parse upper value cmdline with .'-C:'column . parse value cmdline with .'-d:"'delimiter'"'. if delimiter = '' then parse value cmdline with .'-D:"'delimiter'"'. parse upper value cmdline with .'-F:'field . parse upper value cmdline with .'-L:'length . parse upper value cmdline with .'-V:'variable . ipos = pos( ' -I', translate( cmdline ) ) if ipos = 0 then do case = '' end else do if ipos > lastpos( '"', cmdline ) | ipos < pos( '"', cmdline ) then do case = 'upper' delimiter = translate( delimiter ) end else do case = '' end end spos = pos( ' -S', translate( cmdline ) ) if spos = 0 then do skip = 0 end else do if spos > lastpos( '"', cmdline ) | spos < pos( '"', cmdline ) then do skip = 1 end else do skip = 0 end end select when column <> '' & field <> '' then call Syntax when length <> '' & datatype( length, 'W' ) <> 1 then call Syntax when field <> '' then do if datatype( field, 'W' ) <> 1 then call Syntax cuttype = 'WORD' cutpos = field end when column <> '' then do if delimiter <> '' then call Syntax if datatype( column, 'W' ) <> 1 then call Syntax cuttype = 'CHAR' cutpos = column end otherwise call Syntax end cutlen = 0 if length <> '' then cutlen = length if delimiter = '' then delimiter = ' ' if variable = '' then variable = 'CUT' /* Purge variable */ call value variable, "", "OS2ENVIRONMENT" /* Read Standard Input */ empty = 0 do i = 1 by 1 while lines( ) > 0 parse pull line.i if line.i = "00"X then leave if line.i = "1A"X then leave if line.i <> "" then empty = 0 if line.i = "" then empty = empty + 1 /* Stop after 100 empty lines */ if empty > 100 then leave end /* Ignore those 100 empty lines */ line.0 = i - 100 /* Cut lines as specified on command line */ cuttot = cutpos + cutlen do i = 1 to line.0 if line.i = "" then do msg = "" call Output iterate end if cuttype = "CHAR" then do linelen = length( line.i ) if linelen >= cutpos then do select when cutlen = 0 then do msg = substr( line.i, cutpos ) call Output end when cutlen > 0 then do if linelen < cuttot then do msg = substr( line.i, cutpos ) call Output end else do msg = substr( line.i, cutpos, cutlen ) call Output end end otherwise call Syntax end end else do msg = "" call Output end end if cuttype = "WORD" & delimiter = " " then do linelen = words( line.i ) if linelen >= cutpos then do select when cutlen = 0 then do msg = subword( line.i, cutpos ) call Output end when cutlen > 0 then do if linelen < cuttot then do msg = subword( line.i, cutpos ) call Output end else do msg = subword( line.i, cutpos, cutlen ) call Output end end otherwise call Syntax end end else do msg = "" call Output end end if cuttype = "WORD" & delimiter <> " " then do string = line.i dlen = length( delimiter ) do j = 1 by 1 until string = "" interpret 'parse '||case||' value string with word.'||j||'"'||delimiter||'"string' word.0 = j end linelen = word.0 line = word.cutpos if linelen > cutpos then do j = cutpos + 1 by 1 to linelen line = line||delimiter||word.j end if linelen >= cutpos then do select when cutlen = 0 then msg = line when cutlen > 0 then do if linelen < cuttot then do msg = line end else do dpos = 0 do j = 1 to cutlen dpos = pos( delimiter, line, dpos + dlen ) end msg = substr( line, 1, dpos ) end end otherwise call Syntax end call Output end else do msg = "" call Output end end end EXIT Output: if skip = 0 | strip( msg ) <> "" then do if xcommand <> "" then do call value variable, msg, "OS2ENVIRONMENT" address CMD "@CMD /C "||xcommand end else do say msg end end return Syntax: procedure call beep 220, 240 say say " CUT, Version 2.01 for OS/2" say " (C) 1998 - 2000, Rob van der Woude" say " http://www.robvanderwoude.com" say say " Usage: <any_command> | CUT <options>" say say " Options: Function: Dependency" say " __________________________________________________________________________" say say " -C:<column_number> Parse by Columns or Characters" say ' -D:"<delimiter>" Delimiter character or string -F' say " -F:<field_number> Parse by Fields or words" say " -I Case Insensitive delimiter (should -D" say " be the first or last parameter)" say " -L:<string_length> Number of characters to display -C" say " or -L:<fields> Number of fields (words) to display -F" say " -V:<variable_name> Save last result in environment variable" say say " Examples:" say say " ECHO 1234567890 | CUT -C:4" say say ' VER | TIME | CUT -F:2 -D:":" -S -V:TIME -X:TEST.CMD' say " (TEST.CMD should contain one line: ECHO Time is %TIME%)" say EXIT 1 end
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Attempt to "port" the Unix CUT command to Rexx */ /* Rob van der Woude, May 16 1998 - January 4 2003 */ /* Usage: */ /* any_command | CUT { -C:n | -F:n [ -D:"any_string" [ -I ] ] } [ -L:n ] */ /* Note: The -D switch isn't functional yet, so neither is -I */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Specify maximum number of empty lines */ maxEmpty = 50 /* Initialize RexxUtil */ If RxFuncQuery( "sysloadfuncs" ) <> 0 Then Do Call RxFuncAdd "sysloadfuncs", "RexxUtil", "sysloadfuncs" Call sysloadfuncs End /* Parse and check command line */ Parse arg cmdline cmdline = Translate( cmdline, '-', '/' ) cmdline = strip( cmdline ) Parse Upper Value cmdline With .'-C:'column . Parse Value cmdline With .'-d:"'delimiter'"'. If delimiter = '' Then Parse Value cmdline With .'-D:"'delimiter'"'. Parse Upper Value cmdline With .'-F:'field . Parse Upper Value cmdline With .'-L:'length . ipos = Pos( ' -I', Translate( cmdline ) ) If ipos = 0 Then Do case = '' End Else Do If ipos > LastPos( '"', cmdline ) | ipos < Pos( '"', cmdline ) Then Do case = 'Upper' delimiter = Translate( delimiter ) End Else Do case = '' End End spos = Pos( ' -S', Translate( cmdline ) ) If spos = 0 Then Do skip = 0 End Else Do If spos > LastPos( '"', cmdline ) | spos < Pos( '"', cmdline ) Then Do skip = 1 End Else Do skip = 0 End End Select When column <> '' & field <> '' Then Call Syntax When length <> '' & DataType( length, 'W' ) <> 1 Then Call Syntax When field <> '' Then Do If DataType( field, 'W' ) <> 1 Then Call Syntax cuttype = 'WORD' cutpos = field End When column <> '' Then Do If delimiter <> '' Then Call Syntax If DataType( column, 'W' ) <> 1 Then Call Syntax cuttype = 'CHAR' cutpos = column End Otherwise Call Syntax End cutlen = 0 If length <> '' Then cutlen = length If delimiter = '' Then delimiter = ' ' /* Read Standard Input */ empty = 0 Do i = 1 By 1 While Lines( ) > 0 line.i = LineIn( "STDIN" ) If line.i = "00"X Then Leave If line.i = "1A"X Then Leave If line.i = "" Then empty = empty + 1; Else empty = 0 /* Stop after <maxEmpty> empty lines */ If empty > maxEmpty Then Leave End /* Ignore those empty lines */ line.0 = i - empty /* Cut lines as specified on command line */ cuttot = cutpos + cutlen Do i = 1 to line.0 If line.i = "" Then Do msg = "" Call Output Iterate End If cuttype = "CHAR" Then Do linelen = Length( line.i ) If linelen >= cutpos Then Do Select When cutlen = 0 Then Do msg = substr( line.i, cutpos ) Call Output End When cutlen > 0 Then Do If linelen < cuttot Then Do msg = substr( line.i, cutpos ) Call Output End Else Do msg = substr( line.i, cutpos, cutlen ) Call Output End End Otherwise Call Syntax End End Else Do msg = "" Call Output End End If cuttype = "WORD" & delimiter = " " Then Do linelen = Words( line.i ) If linelen >= cutpos Then Do Select When cutlen = 0 Then Do msg = SubWord( line.i, cutpos ) Call Output End When cutlen > 0 Then Do If linelen < cuttot Then Do msg = SubWord( line.i, cutpos ) Call Output End Else Do msg = SubWord( line.i, cutpos, cutlen ) Call Output End End Otherwise Call Syntax End End Else Do msg = "" Call Output End End If cuttype = "WORD" & delimiter <> " " Then Do string = line.i dlen = Length( delimiter ) Do j = 1 by 1 until string = "" interpret 'Parse '||case||' Value string With word.'||j||'"'||delimiter||'"string' word.0 = j End linelen = word.0 line = word.cutpos If linelen > cutpos Then Do j = cutpos + 1 by 1 to linelen line = line||delimiter||word.j End If linelen >= cutpos Then Do Select When cutlen = 0 Then msg = line When cutlen > 0 Then Do If linelen < cuttot Then Do msg = line End Else Do dpos = 0 Do j = 1 to cutlen dpos = Pos( delimiter, line, dpos + dlen ) End msg = substr( line, 1, dpos ) End End Otherwise Call Syntax End Call Output End Else Do msg = "" Call Output End End End /* Normal program end */ Exit 0 Output: If skip = 0 | strip( msg ) <> "" Then Say msg Return Syntax: procedure Call beep 220, 240 Say Say "Cut.rex, Version 0.50 beta for Regina Rexx" Say 'Attempt to "port" the Unix CUT command to Rexx' Say Say "Usage: <any_command> | CUT <options>" Say Say "Options: Function: Dependency" Say "__________________________________________________________________________" Say Say " -C:<column_number> Parse by Columns or Characters" /* Say ' -D:"<delimiter>" Delimiter character or string -F' */ Say " -F:<field_number> Parse by Fields or words" /* Say " -I Case Insensitive delimiter (should -D" */ Say " be the first or last parameter)" Say " -L:<string_length> Number of characters to display -C" Say "or -L:<fields> Number of fields (words) to display -F" Say Say "Examples:" Say Say " ECHO 1234567890 | CUT -C:4" Say " VER | DATE | REGINA CUT.REX -F:6" Say " VER | DATE | REGINA CUT.REX -F:6 | REGINA CUT.REX -C:7" Say Say "Written by Rob van der Woude" Say "http://www.robvanderwoude.com" Exit 1 Return
; False.kix, Version 1.00 ; Port of UNIX' "false" command ; Usage: KIX32 FALSE.KIX || command_to_be_tested ; Written by Rob van der Woude ; http://www.robvanderwoude.com Exit 1
#! perl if ( @ARGV[0] ) { print "\nFalse.pl, Version 1.00\n"; print "Port of UNIX' \"false\" command\n\n"; print "Usage: FALSE.PL || command_to_be_tested\n\n"; print "Written by Rob van der Woude\n"; print "http://www.robvanderwoude.com\n"; } exit(1);
/* Return "false" */ Parse Arg arguments If arguments <> "" Then Do Say "False.rex, Version 1.00" Say "Port of UNIX' "||'"false"'||" command" Say Say "Usage: FALSE.REX || command_to_be_tested" Say Say "Written by Rob van der Woude" Say "http://www.robvanderwoude.com" End Exit 1
@ECHO OFF :: Check Windows version IF NOT "%OS%"=="Windows_NT" GOTO Syntax :: Keep variables local SETLOCAL :: Check command line arguments SET Append=0 IF /I [%1]==[-a] ( SET Append=1 SHIFT ) IF [%1]==[] GOTO Syntax IF NOT [%2]==[] GOTO Syntax :: Test for invalid wildcards SET Counter=0 FOR /F %%A IN ('DIR /A /B %1 2^>NUL') DO CALL :Count "%%~fA" IF %Counter% GTR 1 ( SET Counter= GOTO Syntax ) :: A valid filename seems to have been specified SET File=%1 :: Check if a directory with the specified name exists DIR /AD %File% >NUL 2>NUL IF NOT ERRORLEVEL 1 ( SET File= GOTO Syntax ) :: Specify /Y switch for Windows 2000 / XP COPY command SET Y= VER | FIND "Windows NT" > NUL IF ERRORLEVEL 1 SET Y=/Y :: Flush existing file or create new one if -a wasn't specified IF %Append%==0 (COPY %Y% NUL %File% > NUL 2>&1) :: Actual TEE FOR /F "tokens=1* delims=]" %%A IN ('FIND /N /V ""') DO ( > CON ECHO.%%B >> %File% ECHO.%%B ) :: Done ENDLOCAL GOTO:EOF :Count SET /A Counter += 1 SET File=%1 GOTO:EOF :Syntax ECHO. ECHO Tee.bat, Version 2.11a for Windows NT 4 / 2000 / XP ECHO Display text on screen and redirect it to a file simultaneously ECHO. IF NOT "%OS%"=="Windows_NT" ECHO Usage: some_command │ TEE.BAT [ -a ] filename IF NOT "%OS%"=="Windows_NT" GOTO Skip ECHO Usage: some_command ^| TEE.BAT [ -a ] filename :Skip ECHO. ECHO Where: "some_command" is the command whose output should be redirected ECHO "filename" is the file the output should be redirected to ECHO -a appends the output of the command to the file, ECHO rather than overwriting the file ECHO. ECHO Written by Rob van der Woude ECHO http://www.robvanderwoude.com ECHO Modified by Kees Couprie ECHO http://kees.couprie.org ECHO and Andrew Cameron
using System; using System.Collections.Generic; using System.IO; namespace RobvanderWoude { class Tee { static string progver = "1.03"; static int Main( string[] args ) { #region Command Line Parsing string filename = String.Empty; if ( args.Length == 1 || Console.IsInputRedirected ) { if ( args[0].IndexOf( "?" ) > -1 ) { return ShowHelp( ); } filename = Path.GetFullPath( args[0] ); if ( !Directory.Exists( Path.GetDirectoryName( filename ) ) ) { return ShowHelp( "Invalid parent folder for output file" ); } if ( Directory.Exists( filename ) ) { return ShowHelp( "Please specify an output file name" ); } } else { return ShowHelp( ); } #endregion try { int inputn; string inputc; StreamWriter file = new StreamWriter( filename, true ); do { inputn = Console.In.Read( ); if ( inputn != -1 ) { inputc = Convert.ToChar( Convert.ToByte( inputn ) ).ToString( ); Console.Write( inputc ); file.Write( inputc ); } } while ( inputn != -1 ); file.Close( ); return 0; } catch ( Exception e ) { return ShowHelp( e.Message ); } } #region Error Handling public static int ShowHelp( params string[] errmsg ) { #region Error Message if ( errmsg.Length > 0 ) { List<string> errargs = new List<string>( errmsg ); errargs.RemoveAt( 0 ); Console.Error.WriteLine( ); Console.ForegroundColor = ConsoleColor.Red; Console.Error.Write( "ERROR:\t" ); Console.ForegroundColor = ConsoleColor.White; Console.Error.WriteLine( errmsg[0], errargs.ToArray( ) ); Console.ResetColor( ); } #endregion Error Message #region Help Text /* Tee, Version 1.03 Tee port for Windows: redirect Standard Input to Standard Output AND to a file Usage: somecommand | TEE.EXE filename Where: somecommand command whose output is piped into TEE's Standard Input filename the file that TEE's Standard Input will be appended to Note: This program requires .NET Framework 4.5; use an older version of this program if you don't have .NET Framework 4.5 installed. Written by Rob van der Woude http://www.robvanderwoude.com */ Console.Error.WriteLine( ); Console.Error.WriteLine( "Tee, Version {0}", progver ); Console.Error.WriteLine( "Tee port for Windows: redirect Standard Input to Standard Output AND to a file" ); Console.Error.WriteLine( ); Console.Error.Write( "Usage: " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.WriteLine( "somecommand | TEE.EXE filename" ); Console.ResetColor( ); Console.Error.WriteLine( ); Console.Error.Write( "Where: " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( "somecommand" ); Console.ResetColor( ); Console.Error.WriteLine( " command whose output is piped into TEE's Standard Input" ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( " filename" ); Console.ResetColor( ); Console.Error.WriteLine( " the file that TEE's Standard Input will be appended to" ); Console.Error.WriteLine( ); Console.Error.WriteLine( "Note: This program requires .NET Framework 4.5; use an older version" ); Console.Error.WriteLine( " of this program if you don't have .NET Framework 4.5 installed." ); Console.Error.WriteLine( ); Console.Error.WriteLine( "Written by Rob van der Woude" ); Console.Error.WriteLine( "http://www.robvanderwoude.com" ); #endregion Help Text return 1; } #endregion } }
#! perl # Store help text in a variable $syntax = "\nTee.pl, Version 2.00\n"; $syntax = $syntax."Display text on screen and redirect it to a file simultaneously\n\n"; $syntax = $syntax."Usage: some_command \| PERL.EXE TEE.PL filename\n\n"; $syntax = $syntax."Where: \"some_command\" is the command whose output should be redirected\n"; $syntax = $syntax." \"filename\" is the file the output should be redirected to\n\n"; $syntax = $syntax."Written by Rob van der Woude\nhttp://www.robvanderwoude.com\n"; # Display help and quit if no arguments were specified if ( !$ARGV[0] ) { print $syntax; exit(1); } # Open file for writing, or display help text on error open( OUT, "> $ARGV[0]" ) || die( "\nCannot open file \"$ARGV[0]\"\n\n$syntax" ); # Read and redirect standard input while ( <STDIN> ) { print $_; print OUT $_; } # Close output file close OUT;
/* TEE port */ /* Parse and check command line arguments */ Parse Upper Arg ."/D:"maxwait . If maxwait = "" Then Do Parse Arg outfile dummy maxwait = 1 End Else Do Parse Arg .":"maxwait outfile dummy End If outfile = "" Then Call Syntax If dummy <> "" Then Call Syntax If maxwait = "" Then Call Syntax If DataType( maxwait, "W" ) = 0 Then Call Syntax If maxwait < 1 Then Call Syntax /* Initialize variables */ stopflag = 0 counter = 0 /* Initialize RexxUtil */ If RxFuncQuery( "SysLoadFuncs" ) <> 0 Then Do Call RxFuncAdd "SysLoadFuncs", "RexxUtil", "SysLoadFuncs" End Call SysLoadFuncs /* Read, display and redirect standard input */ Do Until stopflag = 1 If lines( STDIN ) = 0 Then Do counter = counter + 1 If counter > maxwait Then stopflag = 1 Call SysSleep 1 End Else Do Parse Pull line Say line Call LineOut outfile, line End End /* Normal program termination */ Exit 0 Syntax: Say Say "Tee.rex, Version 1.00 for (Regina) Rexx" Say "Port of Unix' TEE command" Say "Redirects its input to the console and to a file simultaneously" Say Say "Usage: any_command | <REXX> TEE.REX [/D:nn] output_file" Say Say 'Where: "any_command" is the command whose output you want to redirect' Say ' "output_file" is the file where any_command'||"'s output is redirected to" Say ' "nn" is the max idle time (in seconds) allowed for any_command' Say ' "<REXX>" is your Rexx interpreter:' Say " - Windows: REGINA.EXE with RexxUtil" Say " - OS/2: no need to specify, just rename script to *.cmd" Say Say "Written by Rob van der Woude" Say "http://www.robvanderwoude.com" Say Exit 1 Return
; True.kix, Version 1.00 ; Port of UNIX' "true" command ; Usage: KIX32 TRUE.KIX && command_to_be_tested ; Written by Rob van der Woude ; http://www.robvanderwoude.com Exit 0
#! perl if ( @ARGV[0] ) { print "\nTrue.pl, Version 1.00\n"; print "Port of UNIX' \"true\" command\n\n"; print "Usage: TRUE.PL && command_to_be_tested\n\n"; print "Written by Rob van der Woude\n"; print "http://www.robvanderwoude.com\n"; } exit(0);
/* Return "true" */ Parse Arg arguments If arguments <> "" Then Do Say "True.rex, Version 1.00" Say "Port of UNIX' "||'"true"'||" command" Say Say "Usage: TRUE.REX && command_to_be_tested" Say Say "Written by Rob van der Woude" Say "http://www.robvanderwoude.com" End Exit 0
@ECHO OFF :: Command line error check: IF "%1"=="" GOTO Syntax :: Check PATH length: SET TEST= FOR %%A IN (.\;%PATH%) DO SET TEST=OK CLS IF NOT "%TEST%"=="OK" GOTO StrLength :: The actual program: ECHO. FOR %%A IN (.\;%PATH%) DO IF EXIST %%A.\%1.BAT TRUENAME %%A.\%1.BAT FOR %%A IN (.\;%PATH%) DO IF EXIST %%A.\%1.EXE TRUENAME %%A.\%1.EXE FOR %%A IN (.\;%PATH%) DO IF EXIST %%A.\%1.COM TRUENAME %%A.\%1.COM FOR %%A IN (.\;%PATH%) DO IF EXIST %%A.\%1 TRUENAME %%A.\%1 GOTO End :: PATH length error message: :StrLength ECHO. ECHO Sorry, your PATH environment variable is too long to ECHO be handled by this batch file. ECHO. ECHO The 127 character command line limit was exceeded ECHO when just testing. GOTO End :: Help screen: :Syntax ECHO. ECHO WHICH, Version 1.00 ECHO UNIX-like WHICH utility for DOS ECHO Written by Rob van der Woude ECHO. ECHO Usage: WHICH program_name ECHO. ECHO You may specify program_name with or without extension, ECHO but without a drive or path. ECHO Spaces or wildcards aren't allowed either. ECHO. ECHO Limitation: This batch file has problems handling long ECHO PATH variables; it will say so, however, ECHO when it encounters this problem. :End ECHO. SET TEST=
@ECHO OFF :: Check Windows version IF "%OS%"=="Windows_NT" (SETLOCAL) ELSE (GOTO Syntax) :: Check command line argument IF "%~1"=="" GOTO Syntax IF NOT "%~2"=="" GOTO Syntax ECHO.%1 | FIND /V ":" | FIND /V "\" | FIND /V "*" | FIND /V "?" | FIND /V "," | FIND /V ";" | FIND /V "/" | FIND "%~1" >NUL IF ERRORLEVEL 1 GOTO Syntax :: If the specified command contains a dot, it is not a macro nor an internal command ECHO.%1 | FIND "." >NUL IF NOT ERRORLEVEL 1 GOTO ExtCmd :: Check if the command specified is a DOSKEY macro FOR /F "tokens=1* delims==" %%A IN ('DOSKEY /MACROS 2^>NUL') DO ( IF /I "%~1"=="%%~A" ( ECHO. ECHO -DOSKEY Macro- GOTO:EOF ) ) :: Next, check if the command specified is an internal command; to do so :: reliably we need SysInternals' STRINGS; if it isn't available, we'll :: just check against a list of known internal commands, risking "false :: positives" in older CMD versions (e.g. MAKELINK does not exist in XP, :: but without STRINGS.EXE this batch file will still return "-CMD :: internal command-"; when STRINGS.EXE IS available, the batch file would :: return "-None-") FOR %%A IN (APPEND ASSOC BREAK CALL CD CHCP CHDIR CLS COLOR COPY DATE DEL DIR DPATH ECHO ENDLOCAL ERASE EXIT FOR FTYPE GOTO IF KEYS MD MKDIR MKLINK MOVE PATH PAUSE POPD PROMPT PUSHD RD REM REN RENAME RMDIR SET SETLOCAL SHIFT START TIME TITLE TRUENAME TYPE VER VERIFY VOL) DO ( IF /I "%~1"=="%%~A" ( STRINGS.EXE /? >NUL 2>&1 IF ERRORLEVEL 1 ( REM * * * NOT TESTED :: may return a false positive * * * ECHO. ECHO -CMD Internal Command- GOTO:EOF ) ELSE ( REM * * * TESTED with STRINGS.EXE :: might still occasionally fail, though * * * STRINGS.EXE "%ComSpec%" | FINDSTR.EXE /R /B /I /C:"%~1$" >NUL IF NOT ERRORLEVEL 1 ( ECHO. ECHO -CMD Internal Command- GOTO:EOF ) ) ) ) :ExtCmd :: Search current directory first, then PATH, for the "pure" :: file name itself or one of the extensions defined in PATHEXT. :: Add quotes to match directory names with spaces as well. SET Path="%CD%";"%Path:;=";"%" SET Found=-None- :: This command line was partly rewritten by Yakov Azulay. FOR %%A IN (%Path%) DO ( ECHO.%~1 | FIND "." >NUL IF ERRORLEVEL 1 ( FOR %%B IN (%PathExt%) DO ( IF EXIST "%%~A.\%~1%%~B" ( CALL :Found "%%~A.\%~1%%~B" ) ) ) ELSE ( FOR %%B IN (.;%PathExt%) DO ( IF EXIST "%%~A.\%~1%%~B" ( CALL :Found "%%~A.\%~1%%~B" ) ) ) ) :: Display the result ECHO. ECHO.%Found% :: Done GOTO End :Found :: Stop after finding the first match IF NOT "%Found%"=="-None-" GOTO:EOF :: Store the first match found SET Found=%~f1 GOTO:EOF :Syntax ECHO. ECHO WHICH, Version 5.20 ECHO UNIX-like WHICH utility for Windows 2000 and later ECHO. ECHO Usage: WHICH program_name ECHO. ECHO Notes: You may specify the program_name with or without extension, but ECHO wildcards, drive, or path are NOT allowed. ECHO This batch file first searches the list of DOSKEY macros, then ECHO the list of CMD's internal commands, then the current directory, ECHO and finally the PATH for the command specified. ECHO If SysInternals' STRINGS is available and in the PATH, CMD's internal ECHO commands will be verified. ECHO If STRINGS is NOT available, internal commands are NOT verified, e.g. ECHO even though MKLINK is not available in XP at all, the command ECHO "WHICH MKLINK" would still return "-CMD internal command-" anyway. ECHO. ECHO Written by Yakov Azulay and Rob van der Woude ECHO http://www.robvanderwoude.com :End IF "%OS%"=="Windows_NT" ENDLOCAL
@ECHO OFF :: Check for NT4 or later IF NOT "%OS%"=="Windows_NT" GOTO Syntax :: Check for XP or later FOR /F "tokens=2 delims=[]" %%A IN ('VER') DO FOR /F "tokens=2" %%B IN ("%%~A") DO IF %%B LSS 5.1 GOTO Syntax :: Check command line argument IF "%~1"=="" GOTO Syntax IF NOT "%~2"=="" IF /I NOT "%~2"=="/A" GOTO Syntax ECHO.%1 | FINDSTR /R /C:"[:\\\*\?,;/]" >NUL && GOTO Syntax :: If the specified command contains a dot, it is not a macro nor an internal command ECHO.%1 | FIND "." >NUL && GOTO ExtCmd :: Check if the command specified is a DOSKEY macro FOR /F "tokens=1* delims==" %%A IN ('DOSKEY /MACROS 2^>NUL') DO ( IF /I "%~1"=="%%~A" ( ECHO. ECHO -DOSKEY Macro- IF /I NOT "%~2"=="/A" GOTO:EOF ) ) :: Next, check if the command specified is an internal command; to do so :: reliably we need SysInternals' STRINGS; if it isn't available, we'll :: just check against a list of known internal commands, risking "false :: positives" in older CMD versions (e.g. MAKELINK does not exist in XP, :: but without STRINGS.EXE this batch file will still return "-CMD :: internal command-"; when STRINGS.EXE IS available, the batch file would :: return "-None-") FOR %%A IN (APPEND ASSOC BREAK CALL CD CHCP CHDIR CLS COLOR COPY DATE DEL DIR DPATH ECHO ENDLOCAL ERASE EXIT FOR FTYPE GOTO IF KEYS MD MKDIR MKLINK MOVE PATH PAUSE POPD PROMPT PUSHD RD REM REN RENAME RMDIR SET SETLOCAL SHIFT START TIME TITLE TRUENAME TYPE VER VERIFY VOL) DO ( IF /I "%~1"=="%%~A" ( STRINGS.EXE /? >NUL 2>&1 IF ERRORLEVEL 1 ( REM * * * NOT TESTED :: may return a false positive * * * ECHO. ECHO -CMD Internal Command- IF /I NOT "%~2"=="/A" GOTO:EOF ) ELSE ( REM * * * TESTED with STRINGS.EXE :: might still occasionally fail, though * * * STRINGS.EXE "%ComSpec%" | FINDSTR.EXE /R /B /I /C:"%~1$" >NUL IF NOT ERRORLEVEL 1 ( ECHO. ECHO -CMD Internal Command- IF /I NOT "%~2"=="/A" GOTO:EOF ) ) ) ) :ExtCmd SETLOCAL ENABLEDELAYEDEXPANSION :: Search current directory first, then PATH, for the "pure" :: file name itself or one of the extensions defined in PATHEXT. :: Add quotes to match directory names with spaces as well. :: This command line was partly rewritten by David Riemens. SET SRCH_PATH=.\;%PATH% SET Found=-None- FOR %%A IN (.;%PathExt%) DO ( IF "!Found!"=="-None-" ( FOR %%B IN ("%~1%%~A") DO ( IF NOT "%%~$SRCH_PATH:B"=="" ( FOR %%C IN ("%%~$SRCH_PATH:B") DO SET Test=%%~xC IF NOT "!Test!"=="" IF NOT "!Test!"=="." ( ECHO.%%~$SRCH_PATH:B IF /I NOT "%~2"=="/A" ( ENDLOCAL GOTO:EOF ) ) ) ) ) ) :: No success so far...? IF /I NOT "%~2"=="/A" ECHO -None- :: Done ENDLOCAL GOTO:EOF :Syntax ECHO WHICH, Version 6.11 ECHO UNIX-like WHICH utility for Windows XP and later ECHO. ECHO Usage: WHICH progname [ /A ] ECHO. ECHO Where: progname is the name of the program to locate ECHO /A lists all occurrences, not just the first one ECHO. ECHO Returns: "-DOSKEY Macro-", "-CMD Internal Command-", or the fully qualified ECHO path to the first matching program found in the PATH, based on the ECHO specified extension or the ones listed in PATHEXT; or "-None-". ECHO. ECHO Notes: progname MAY include extension; wildcards, drive, path NOT allowed. ECHO This batch file first searches the list of DOSKEY macros, then CMD's ECHO internal commands, then current directory, finally PATH for progname. ECHO Only if SysInternals' STRINGS is available and in the PATH, CMD's ECHO internal commands will be verified; e.g. even though MKLINK is not ECHO available in XP at all, without STRINGS the command "WHICH MKLINK" ECHO would still return "-CMD internal command-" anyway. ECHO When the /A switch is used, nothing is returned when nothing is found ECHO (unlike without /A switch, where "-None-" would be returned). ECHO. ECHO Written by David Riemens and Rob van der Woude :: The things you need to do to make the text fit in 80 columns and 25 lines... IF NOT "%OS%"=="Windows_NT" ECHO http://www.robvanderwoude.com IF "%OS%"=="Windows_NT" SET /P "=http://www.robvanderwoude.com" < NUL IF "%OS%"=="Windows_NT" EXIT /B 1
using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Text; using System.Text.RegularExpressions; using System.Windows.Forms; namespace RobvanderWoude { class Which { public static string progver = "1.48"; public static char switchchar = '/'; [STAThread] static int Main( string[] args ) { #region Initialize Variables string[] path = String.Format( "{0};{1}", Environment.CurrentDirectory, Environment.GetEnvironmentVariable( "PATH" ) ).Split( ";".ToCharArray( ), StringSplitOptions.RemoveEmptyEntries ); string[] pathext = ( ";" + Environment.GetEnvironmentVariable( "PATHEXT" ).ToLower( ) ).Split( ';' ); // unlike PATH, do NOT remove empty entries, we REQUIRE the first one to be empty string prog = string.Empty; string result = String.Empty; bool all = false; bool copy = false; bool extonly = false; bool filever = false; bool openexp = false; bool prodver = false; bool set_all = false; bool set_copy = false; bool set_exp = false; bool set_ext = false; bool set_fver = false; bool set_prog = false; bool set_pver = false; bool found = false; #endregion Initialize Variables #region Command Line Parsing if ( args.Length == 0 ) { return WriteError( ); } int scd = 0; int scu = 0; foreach ( string arg in args ) { if ( arg[0] == '-' ) { scu += 1; } if ( arg[0] == '/' ) { scd += 1; } if ( arg == "/?" ) { return WriteError( ); } if ( arg == "-?" || arg == "-h" || arg == "--help" ) { switchchar = '-'; return WriteError( ); } } if ( scu > scd ) { switchchar = '-'; } foreach ( string arg in args ) { if ( arg[0] == '/' || arg[0] == '-' ) { if ( arg.Length != 2 ) { return WriteError( "Invalid command line switch {0}", ( switchchar == '/' ? arg.ToUpper( ) : arg.ToLower( ) ) ); } switch ( arg[1].ToString( ).ToUpper( ) ) { case "A": if ( set_all ) { return WriteError( "Duplicate command line switch {0}", SwitchString( arg[1] ) ); } if ( set_exp ) { return WriteError( "Command line switches {0} and {1} are mutually exclusive", SwitchString( arg[1] ), SwitchString( "E" ) ); } all = true; set_all = true; break; case "C": if ( set_copy ) { return WriteError( "Duplicate command line switch {0}", SwitchString( arg[1] ) ); } copy = true; set_copy = true; break; case "E": if ( set_exp ) { return WriteError( "Duplicate command line switch {0}", SwitchString( arg[1] ) ); } if ( set_all ) { return WriteError( "Command line switches {0} and {1} are mutually exclusive", SwitchString( "A" ), SwitchString( arg[1] ) ); } openexp = true; set_exp = true; break; case "F": if ( set_fver ) { return WriteError( "Duplicate command line switch {0}", SwitchString( arg[1] ) ); } if ( set_pver ) { return WriteError( "Command line switches {0} and {1} are mutually exclusive", SwitchString( arg[1] ), SwitchString( "P" ) ); } filever = true; set_fver = true; break; case "P": if ( set_pver ) { return WriteError( "Duplicate command line switch {0}", SwitchString( "P" ) ); } if ( set_fver ) { return WriteError( "Command line switches {0} and {1} are mutually exclusive", SwitchString( "F" ), SwitchString( arg[1] ) ); } prodver = true; set_pver = true; break; case "X": if ( set_ext ) { return WriteError( "Duplicate command line switch {0}", SwitchString( arg[1] ) ); } extonly = true; set_ext = true; break; case "?": return WriteError( ); default: return WriteError( "Invalid command line switch {0}", ( switchchar == '/' ? arg.ToUpper( ) : arg.ToLower( ) ) ); } } else { if ( set_prog ) { return WriteError( "Invalid or duplicate command line argument: \"{0}\"", arg ); } else { char[] forbidden = { '\\', '?', '*', ':', ';', '/' }; if ( arg.IndexOfAny( forbidden ) == -1 ) { prog = arg; set_prog = true; } else { return WriteError( "Invalid characters in specified program name: \"{0}\"", arg ); } } } } #endregion Command Line Parsing try { if ( !extonly ) { #region DOSKEY macros // Try DOSKEY macros first Process doskey = new Process( ); doskey.StartInfo.Arguments = "/macros"; doskey.StartInfo.CreateNoWindow = false; doskey.StartInfo.FileName = Environment.GetFolderPath( Environment.SpecialFolder.System ) + "\\doskey.exe"; doskey.StartInfo.LoadUserProfile = false; doskey.StartInfo.RedirectStandardError = false; doskey.StartInfo.RedirectStandardInput = false; doskey.StartInfo.RedirectStandardOutput = true; doskey.StartInfo.UseShellExecute = false; doskey.Start( ); doskey.WaitForExit( 1000 ); do { string line = doskey.StandardOutput.ReadLine( ); if ( !found || all ) { if ( !String.IsNullOrEmpty( line ) ) { if ( line.IndexOf( '=' ) > 0 ) { string pattern = "^" + prog.ToUpper( ).Replace( ".", "\\." ) + "="; if ( Regex.IsMatch( line.ToUpper( ), pattern ) ) { Console.ForegroundColor = ConsoleColor.White; Console.Write( "[{0}]::", doskey.StartInfo.FileName.ToUpper( ) ); Console.ResetColor( ); Console.WriteLine( line ); result += String.Format( "[{0}]::{1}\n", doskey.StartInfo.FileName.ToUpper( ), line ); found = true; } } } } } while ( doskey.StandardOutput.Peek( ) != -1 ); doskey.Close( ); #endregion DOSKEY macros #region Internal commands // Next try internal commands if ( !found || all ) { if ( prog.IndexOf( '.' ) == -1 ) { if ( ListInternalCommands( ).Contains( prog.ToUpper( ) ) ) { Console.ForegroundColor = ConsoleColor.White; Console.Write( "[{0}]::", Environment.GetEnvironmentVariable( "COMSPEC" ).ToUpper( ) ); Console.ResetColor( ); Console.WriteLine( prog.ToUpper( ) ); result += String.Format( "[{0}]::{1}\n", Environment.GetEnvironmentVariable( "COMSPEC" ).ToUpper( ), prog.ToUpper( ) ); found = true; } } } #endregion Internal commands } #region External commands // Finally try external commands if ( !found || all ) { foreach ( string folder in path ) { if ( !found || all ) { string dir = ( folder + @"\" ).Replace( @"\\", @"\" ); foreach ( string ext in pathext ) { if ( !found || all ) { // The EXTERNAL program FILE to be searched MUST have an extension, either // specified on the command line or one of the extensions listed in PATHEXT. if ( ( prog + ext ).IndexOf( '.' ) > -1 ) { if ( File.Exists( dir + prog + ext ) ) { string ver = String.Empty; if ( filever ) { string fileversion = FileVersionInfo.GetVersionInfo( dir + prog + ext ).FileVersion; if ( String.IsNullOrEmpty( fileversion ) ) { ver = String.Empty; } else { ver = String.Format( " (file version {0})", fileversion ); } } else if ( prodver ) { string productversion = FileVersionInfo.GetVersionInfo( dir + prog + ext ).ProductVersion; if ( String.IsNullOrEmpty( productversion ) ) { ver = String.Empty; } else { ver = String.Format( " (product version {0})", productversion ); } } Console.WriteLine( dir + prog + ext + ver ); result += String.Format( "{0}{1}{2}{3}\n", dir, prog, ext, ver ); found = true; } } } } } } } #endregion External commands if ( found ) { #region Copy to clipboard if ( copy ) { if ( !all ) { result = result.TrimEnd( "\n".ToCharArray( ) ); } Clipboard.SetText( result ); } #endregion Copy to clipboard #region Open In Explorer if ( openexp ) { string file = result.TrimEnd( "\n".ToCharArray( ) ); string sel = String.Format( "/Select, {0}", file ); ProcessStartInfo expl = new ProcessStartInfo( "Explorer.exe", sel ); System.Diagnostics.Process.Start( expl ); } #endregion Open In Explorer return 0; } else { return 1; } } catch ( Exception e ) { return WriteError( e.Message ); } } public static List<string> ListInternalCommands( ) { string comspec = Environment.GetEnvironmentVariable( "COMSPEC" ); StreamReader file = new StreamReader( comspec, Encoding.ASCII ); string content = file.ReadToEnd( ); file.Close( ); bool include = false; List<string> intcmds = new List<string>( ); string excludestr = "ABOVENORMAL,AFFINITY,ANSI,APPICON,ASCII,AZ,BAT,BELOWNORMAL,BOTH,CMD,CMDCMDLINE,CMDEXTVERSION,COM,COMSPEC,CONFIG,COPYCMD,COPYRIGHT,CRLF,CSVFS,CTRL,CURRENT,DEFINED,DIRCMD,DISABLEDELAYEDEXPANSION,DISABLEEXTENSIONS,DLL,DO,DOC,DOS,DWORD,ENABLEDELAYEDEXPANSION,ENABLEEXTENSIONS,ELSE,ENTER,EOF,EQU,ERROR,ERRORLEVEL,EXE,EXIST,EXISTS,EXPAND,FALSE,FAT,FH,GEQ,GTR,GUI,HIGH,HIGHESTNUMANODENUMBER,HH,HKEY,HSM,IDI,IDLE,IN,INFO,IS,JS,KERNEL,LEQ,LIST,LNK,LOCAL,LOW,LSS,MACHINE,MAX,MIN,MM,MSC,MUI,NEQ,NODE,NORMAL,NOT,NT,NTDLL,NTFS,NY,NYA,OFF,ON,OTHER,PATHEXT,PROCESSING,RANDOM,REALTIME,REFS,REG,REGEDT,SCRIPT,SEPARATE,SHARED,STACK,SYS,SZ,TEMP,TWO,UNC,UNCC,UNKNOWN,US,USER,VAR,VBS,VERSION,VS,WAIT,WA,WC,WD,WINDOWS,WKERNEL,WORD,WP,WS,WV,XCOPY,XP"; string[] excludearr = excludestr.Split( ",".ToCharArray( ) ); List<string> exclude = new List<string>( excludearr ); // Optimized for .NET Framework 2.0; in .NET Framework 3.5+ we might have used List<string> exclude = excludestr.Split( ",".ToCharArray( ) ).ToList<string>( ); string pattern = @"([A-Z]\0){2,}"; Regex regex = new Regex( pattern ); if ( regex.IsMatch( content ) ) { foreach ( Match match in regex.Matches( content ) ) { string intcmd = match.ToString( ).Replace( "\0", String.Empty ); if ( intcmd == "CD" ) // The start of the commands list, as found in Windows 7 SP1, EN-GB { include = true; } if ( intcmd == "ERRORLEVEL" ) // The end of the commands list, as found in Windows 7 SP1, EN-GB { include = false; } if ( include && !exclude.Contains( intcmd ) && !intcmds.Contains( intcmd ) ) { intcmds.Add( intcmd ); } } intcmds.Sort( ); } if ( intcmds.Count == 0 ) { // Return a default list if we could not find the internal commands in %COMSPEC% string defaultinternalcommands = @"ASSOC,BREAK,CALL,CD,CHDIR,CLS,COLOR,COPY,DATE,DEL,DIR,DPATH,ECHO,ENDLOCAL,ERASE,EXIT,FOR,FTYPE,GOTO,IF,KEYS,MD,MKDIR,MKLINK,MOVE,PATH,PAUSE,POPD,PROMPT,PUSHD,RD,REM,REN,RENAME,RMDIR,SET,SETLOCAL,SHIFT,START,TIME,TITLE,TYPE,VER,VERIFY,VOL"; string[] defaultintcmdarr = defaultinternalcommands.Split( ",".ToCharArray( ), StringSplitOptions.RemoveEmptyEntries ); intcmds = new List<string>( defaultintcmdarr ); } return intcmds; } public static string SwitchString( char sw ) { return SwitchString( sw.ToString( ) ); } public static string SwitchString( string sw ) { if ( switchchar == '-' ) { return String.Format( "{0}{1}", switchchar, sw.ToLower( ) ); } else { return String.Format( "{0}{1}", switchchar, sw.ToUpper( ) ); } } public static int WriteError( params string[] errmsg ) { /* Which, Version 1.47 Port of the UNIX command to Windows Usage: WHICH progname [ /A | /E ] [ /C ] [ /F | /P ] [ /X ] Where: progname the program name or internal command to be searched for /A returns All matches (default: stop at first match) /C Copies result to clipboard /E opens Explorer with result selected, if it is a file /F returns name and File version for external commands /P returns name and Product version for external commands /X returns eXternal commands only, no DOSKEY macros or internal commands (default: all types) Note: By default, this program first compares the specified name against a list of active DOSKEY macros, next against a list of CMD's internal commands, and finally it tries to find a matching program file in the current directory and the PATH, using the extensions listed in PATHEXT. Written by Rob van der Woude http://www.robvanderwoude.com */ if ( errmsg.Length > 0 ) { List<string> errargs = new List<string>( errmsg ); errargs.RemoveAt( 0 ); Console.Error.WriteLine( ); Console.ForegroundColor = ConsoleColor.Red; Console.Error.Write( "ERROR: " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.WriteLine( errmsg[0], errargs.ToArray( ) ); Console.ResetColor( ); } Console.Error.WriteLine( ); Console.Error.WriteLine( "Which, Version {0}", progver ); Console.Error.WriteLine( "Port of the UNIX command to Windows" ); Console.Error.WriteLine( ); Console.Error.Write( "Usage: " ); Console.ForegroundColor = ConsoleColor.White; if ( switchchar == '/' ) { Console.Error.WriteLine( "WHICH progname [ /A | /E ] [ /C ] [ /F | /P ] [ /X ]" ); } else { Console.Error.WriteLine( "which progname [ -a | -e ] [ -c ] [ -f | -p ] [ -x ]" ); } Console.ResetColor( ); Console.Error.WriteLine( ); Console.Error.Write( "Where: " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( "progname" ); Console.ResetColor( ); Console.Error.WriteLine( " the program name or internal command to be searched for" ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( " {0}", SwitchString( "A" ) ); Console.ResetColor( ); Console.Error.Write( " returns " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( "A" ); Console.ResetColor( ); Console.Error.WriteLine( "ll matches (default: stop at first match)" ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( " {0} C", SwitchString( "C" ) ); Console.ResetColor( ); Console.Error.WriteLine( "opies result to clipboard" ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( " {0}", SwitchString( "E" ) ); Console.ResetColor( ); Console.Error.Write( " opens " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( "E" ); Console.ResetColor( ); Console.Error.Write( "xplorer with result selected, " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( "if" ); Console.ResetColor( ); Console.Error.WriteLine( " it is a file" ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( " {0}", SwitchString( "F" ) ); Console.ResetColor( ); Console.Error.Write( " returns name and " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( "F" ); Console.ResetColor( ); Console.Error.WriteLine( "ile version for external commands" ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( " {0}", SwitchString( "P" ) ); Console.ResetColor( ); Console.Error.Write( " returns name and " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( "P" ); Console.ResetColor( ); Console.Error.WriteLine( "roduct version for external commands" ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( " {0}", SwitchString( "X" ) ); Console.ResetColor( ); Console.Error.Write( " returns e" ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( "X" ); Console.ResetColor( ); Console.Error.WriteLine( "ternal commands only, no DOSKEY macros or" ); Console.Error.WriteLine( " internal commands (default: all types)" ); Console.Error.WriteLine( ); Console.Error.WriteLine( "Note: By default, this program first compares the specified name against" ); Console.Error.WriteLine( " a list of active DOSKEY macros, next against a list of CMD's" ); Console.Error.WriteLine( " internal commands, and finally it tries to find a matching program" ); Console.Error.WriteLine( " file in the current directory and the PATH, using the extensions" ); Console.Error.WriteLine( " listed in PATHEXT." ); Console.Error.WriteLine( ); Console.Error.WriteLine( "Written by Rob van der Woude" ); Console.Error.WriteLine( "http://www.robvanderwoude.com" ); return 1; } } }
; Check command line argument If $search = "" OR InStr( $search, "?" ) ? "Which.kix, Version 1.00" ? "Locate the specified program file" ? "Port of Unix' WHICH command" ? ? "Usage: KIX32 WHICH.KIX $$SEARCH=filename[.ext]" ? ? "Where: " + Chr(34) + "filename" + Chr(34) " is a file name only: no path, no wildcards" ? ? "Written by Rob van der Woude" ? "http://www.robvanderwoude.com" ? Exit 2 EndIf ; Store PATH and PATHEXT in arrays $pathArray = Split( "@CurDir;%PATH%", ";", -1 ) $pathExtArray = Split( "%PATHEXT%;.DLL;.SYS;.OCX", ";", -1 ) ; Reset search result variable $found = 0 ; Search each directory until one match is found For Each $i In $pathArray If $found = 0 $pathDir = $i ; Strip trailing backslash and/or dot If Right( $i, 2 ) = "\." $pathDir = SubStr( $i, 1, Len( $i ) - 2 ) Else If Right( $i, 1 ) = "\" $pathDir = SubStr( $i, 1, Len( $i ) -1 ) EndIf EndIf ; Try without appending extension first If InStr( $search, "." ) If Exist( $pathDir + "\" + $search ) $result = $pathDir + "\" + $search $found = 1 EndIf Else ; Then try all the extensions from PATHEXT For Each $j In $pathExtArray If Exist( $pathDir + "\" + $search + $j ) $result = $pathDir + "\" + $search + $j $found = 1 EndIf Next EndIf EndIf Next ; Display the result If $found = 0 ? "-None-" ? $ret = 1 Else ? $result ? $ret = 0 EndIf ; Exit with return code Exit $ret
#! perl # Check command line argument(s) if ( !@ARGV[0] or @ARGV[1] or !( @ARGV[0] =~ m/^[-\w]+(\.\w+)?$/ ) ) { print "\nWhich.pl, Version 2.00\n"; print "Locate the specified program file\n"; print "Port of Unix' WHICH command\n\n"; print "Usage: WHICH.PL filename[.ext]\n\n"; print "Where: \"filename\" is a file name only: no path, no wildcards\n\n"; print "Note: This script ignores DOSKEY macros and internal commands, and\n"; print " returns external commands (executable or script file names) only.\n\n"; print "Written by Rob van der Woude\n"; print "http://www.robvanderwoude.com\n"; exit(2); } # Store PATH and PATHEXT in arrays while ( ( $key, $value ) = each %ENV ) { if ( uc( $key ) eq "PATH" ) { # Current directory must be searched before the PATH @path = ( ".", split( /;+/,$value ) ); } elsif ( uc( $key ) eq "PATHEXT" ) { # Search for "non-executable" program files too @pathext = ( split( /;+/,$value ) ); } } # Search code in labelled block, to allow quitting the loop SEARCH: { # Search each directory specified in PATH foreach ( @path ) { $d = $_; # Remove trailing backslash or backslash plus dot $d =~ s/^(.*)\\\.?$/\1/; # Read the directory (files only) opendir( SEARCHDIR, $d ) or die "Cannot open directory $d:\n$!"; readdir ( SEARCHDIR ); @files = grep { -f "$d\\$_" } readdir( SEARCHDIR ); foreach $file ( @files ) { # Check for specified file name both with # and without each extension from PATHEXT if ( @ARGV[0] =~ m/^[^.]=\.[^.]+$/ ) { if ( $file =~ m/^@ARGV[0]$/i ) { # Display result print "\n$d\\$file\n"; # Close directory handle closedir( SEARCHDIR ); # Abort search at first successful find last SEARCH; } } else { foreach $ext ( @pathext ) { if ( $file =~ m/^@ARGV[0]($ext)$/i ) { # Display result print "\n$d\\$file\n"; # Close directory handle closedir( SEARCHDIR ); # Abort search at first successful find last SEARCH; } } } } # Close directory handle closedir( SEARCHDIR ); } # If you arrived here, the search was unsuccessful print "\n-None-\n"; exit(1); }
# Which.ps1, Version 1.00 # Locate the specified program file # Port of Unix' WHICH command # # Usage: WHICH.PS1 filename[.ext] # # Where: "filename" is a file name only: no drive or path # # Written by Rob van der Woude # http://www.robvanderwoude.com param([string] $file=$(throw "Please specify a filename.")) (get-command $file).Definition
/* WHICH, Version 3.00 */ /* Rexx "port" of UNIX' WHICH command */ /* that also looks for DLL's in LIBPATH */ /* Written by Rob van der Woude */ /* Initialize RexxUtil */ if RxFuncQuery( "SysLoadFuncs" ) <> 0 then do call RxFuncAdd "SysLoadFuncs", "RexxUtil", "SysLoadFuncs" call SysLoadFuncs end /* Parse command line parameters */ parse upper arg params invalid.0 = 7 invalid.1 = "*" invalid.2 = "?" invalid.3 = "/" invalid.4 = "\" invalid.5 = "," invalid.6 = ";" invalid.7 = ":" do i = 1 to invalid.0 if pos( invalid.i, params ) > 0 then call Syntax end parse value params with dummy1'"'longfilename'"'dummy2 if longfilename <> "" then do if dummy1||dummy2 <> "" then call Syntax filename = longfilename longname = 1 end else do parse value params with filename dummy if filename <> "" then do if dummy <> "" then call Syntax longname = 0 end else do call Syntax end end /* Check if extension was given */ commandext.0 = 5 commandext.1 = ".BAT" commandext.2 = ".CMD" commandext.3 = ".COM" commandext.4 = ".EXE" commandext.5 = ".DLL" addext = 1 chk4ext = right( filename, 4 ) do i = 1 to commandext.0 if chk4ext = commandext.i then addext = 0 end /* Read PATH from environment */ path = translate( value( "PATH", , "OS2ENVIRONMENT" ) ) if chk4ext = ".DLL" then do parse value path with ":\OS2\SYSTEM" -1 bootdrive +2 configsys = bootdrive||"\CONFIG.SYS" call linein configsys, 1, 0 do until lines( configsys ) = 0 line = strip( translate( linein( configsys ) ) ) if left( line, 8 ) = "LIBPATH=" then do parse value line with "LIBPATH="path leave end end end path. = "" path.0 = 1 path.1 = strip( directory( ), "T", "\" )||"\" do i = 2 by 1 until path = "" parse value path with path.i";"path if right( path.i, 1 ) <> "\" then path.i = path.i||"\" path.0 = i end /* Check if file can be found in PATH */ do i = 1 to path.0 until found.0 = 1 if addext = 0 then do file = path.i||filename if longname = 1 then do file = translate( file, "?", " " ) end call SysFileTree file, "found.", "FO" if found.0 = 1 then do if longname = 0 then do call FileFound file end else do file = translate( translate( file, " ", "?" ) ) if file = translate( found.1 ) then do call FileFound file end end end end else do j = 1 to commandext.0 file = path.i||filename||commandext.j if longname = 1 then do file = translate( file, "?", " " ) end call SysFileTree file, "found.", "FO" if found.0 = 1 then do if longname = 0 then do call FileFound file end else do file = translate( translate( file, " ", "?" ) ) if file = translate( found.1 ) then do call FileFound file end end end end end say "Not found: "||filename EXIT 1 FileFound: if longname = 1 then do say 'Found: "'||arg( 1 )||'"' end else do say "Found: "||arg( 1 ) end EXIT 0 return Syntax: procedure say say "WHICH, Version 3.00" say "UNIX-like WHICH utility for OS/2 that" say "can search for DLL's in LIBPATH as well" say "Written by Rob van der Woude" say say "Usage: WHICH program_name" say say " or: WHICH dll_name.DLL" say say "You may specify program_name with or without" say "extension. program_name as well as dll_name.DLL" say "should be specified without a drive or path." say say "Spaces in long file names are allowed, wildcards" say "aren't." EXIT 9 return
/* WHICH, Version 1.00 for Windows */ /* Rexx "port" of UNIX' WHICH command */ /* that also looks for DLL's */ /* Written by Rob van der Woude */ /* Initialize RexxUtil */ If RxFuncQuery( "SysLoadFuncs" ) <> 0 Then Do Call RxFuncAdd "SysLoadFuncs", "RexxUtil", "SysLoadFuncs" Call SysLoadFuncs End /* Display empty line */ Say /* Parse command line parameters */ Parse Upper Arg params invalid.0 = 7 invalid.1 = "*" invalid.2 = "?" invalid.3 = "/" invalid.4 = "\" invalid.5 = "," invalid.6 = ";" invalid.7 = ":" Do i = 1 To invalid.0 If Pos( invalid.i, params ) > 0 Then Call Syntax End Parse Value params With dummy1'"'longfilename'"'dummy2 If longfilename <> "" Then Do If dummy1||dummy2 <> "" Then Call Syntax filename = longfilename longname = 1 End Else Do Parse Value params With filename dummy If filename <> "" Then Do If dummy <> "" Then Call Syntax longname = 0 End Else Do Call Syntax End End /* Check if extension was given */ pathext = Translate( Value( "PATHEXT", , "ENVIRONMENT" ) ) Do i = 1 By 1 Until pathext = "" Parse Value pathext With commandext.i";"pathext If commandext.i <> "" Then commandext.0 = i End i = commandext.0 + 1 commandext.i = ".DLL" i = commandext.0 + 2 commandext.i = ".SYS" i = commandext.0 + 3 commandext.i = ".OCX" commandext.0 = i addext = 1 chk4ext = Right( filename, 4 ) Do i = 1 To commandext.0 If chk4ext = commandext.i Then addext = 0 End /* Read PATH from environment */ path = Translate( Value( "PATH", , "ENVIRONMENT" ) ) path. = "" path.0 = 1 /* Add current directory as first PATH entry */ path.1 = Strip( Directory( ), "T", "\" )||"\" Do i = 2 By 1 Until path = "" Parse Value path With path.i";"path If Right( path.i, 1 ) <> "\" Then path.i = path.i||"\" path.0 = i End /* Check if file can be found in PATH */ Do i = 1 To path.0 Until found.0 = 1 If addext = 0 Then Do file = path.i||filename If longname = 1 Then Do file = Translate( file, "?", " " ) End Call SysFileTree file, "found.", "FO" If found.0 = 1 Then Do If longname = 0 Then Do Call FileFound file End Else Do file = Translate( Translate( file, " ", "?" ) ) If file = Translate( found.1 ) Then Do Call FileFound file End End End End Else Do j = 1 To commandext.0 - 3 file = path.i||filename||commandext.j If longname = 1 Then Do file = Translate( file, "?", " " ) End Call SysFileTree file, "found.", "FO" If found.0 = 1 Then Do If longname = 0 Then Do Call FileFound file End Else Do file = Translate( Translate( file, " ", "?" ) ) If file = Translate( found.1 ) Then Do Call FileFound file End End End End End Say "Not found: "||filename Exit 1 FileFound: If longname = 1 Then Do Say 'Found: "'||arg( 1 )||'"' End Else Do Say "Found: "||arg( 1 ) End Exit 0 Return Syntax: Procedure Say Say "Which.rex, Version 1.00 for Regina Rexx for Windows" Say "UNIX-like WHICH utility for Windows that can search for" Say ".DLL, .OCX and .SYS files as well" Say Say "Usage: WHICH program_name" Say Say 'Where: "program_name" is any program name with or without extension,' Say " but always without drive and/or path." Say Say "Returns: The first file with a valid or specified extension found in the PATH." Say Say "If program_name is specified without extension, all extensions from the PATHEXT" Say "environment variable will be searched for." Say "Files with .DLL, .OCX or .SYS extension will be ignored unless the extension is" Say "specified." Say "Spaces in long file names are allowed, wildcards aren't." Say Say "Written by Rob van der Woude" Say "http://www.robvanderwoude.com" Exit 9 Return
Option Explicit Dim arrFound, arrInt, arrPath, arrPathExt, arrTemp Dim blnAll, blnClipboard, blnExtOnly, blnHasExt, blnQuiet, blnShort, blnVer Dim i, intArgs, j Dim objFile, objFSO, objIE, wshShell Dim strComSpec, strExt, strIntAll, strIntCmd, strIntCom, strPath, strPathExt, strResult, strTime, strVer ' Initialize variables intArgs = 0 strResult = "" With WScript.Arguments ' Check the command line for exactly 1 argument (the file ' name), which should NOT contain wildcard characters If .Unnamed.Count <> 1 Then Syntax If InStr( .Unnamed(0), "*" ) Then Syntax If InStr( .Unnamed(0), "?" ) Then Syntax ' Check the command line switches If .Named.Exists( "A" ) Then blnAll = True intArgs = intArgs + 1 Else blnAll = False End If If .Named.Exists( "C" ) Then blnClipboard = True intArgs = intArgs + 1 Else blnClipboard = False End If If .Named.Exists( "Q" ) Then ' /Q can only be used with /C If blnClipboard Then blnQuiet = True intArgs = intArgs + 1 Else Syntax End If Else blnQuiet = False End If If .Named.Exists( "S" ) Then blnShort = True intArgs = intArgs + 1 Else blnShort = False End If If .Named.Exists( "V" ) Then blnVer = True intArgs = intArgs + 1 Else blnVer = False End If If .Named.Exists( "X" ) Then blnExtOnly = True intArgs = intArgs + 1 Else blnExtOnly = False End If ' Check for remaining invalid command line switches If intArgs <> .Named.Count Then Syntax End With ' Create the required objects Set objFSO = CreateObject( "Scripting.FileSystemObject" ) Set wshShell = CreateObject( "Wscript.Shell" ) ' Define internal command lists strIntAll = "BREAK CALL CD CHCP CHDIR CLS COPY DATE DEL DIR ECHO ERASE " _ & "EXIT FOR GOTO IF MD MKDIR MOVE PATH PAUSE PROMPT RD REM " _ & "REN RENAME RMDIR SET SHIFT TIME TYPE VER VERIFY VOL " strIntCmd = "ASSOC COLOR ENDLOCAL FTYPE POPD PUSHD SETLOCAL START TITLE" strIntCom = "CTTY LFNFOR LH LOADHIGH LOCK TRUENAME UNLOCK" ' Determine the type of command processor ' used: COMMAND.COM or CMD.EXE strComSpec = UCase( wshShell.ExpandEnvironmentStrings( "%COMSPEC%" ) ) If Right( strComSpec, 12 ) = "\COMMAND.COM" Then arrInt = Split( strIntAll & strIntCom ) End If If Right( strComSpec, 8 ) = "\CMD.EXE" Then arrInt = Split( strIntAll & strIntCmd ) End If ' Read the PATH and PATHEXT variables, and store their values in ' arrays; the current directory is prepended to the PATH first strPath = wshShell.CurrentDirectory & ";" _ & wshShell.ExpandEnvironmentStrings( "%PATH%" ) strPathExt = wshShell.ExpandEnvironmentStrings( "%PATHEXT%" ) arrPath = Split( strPath, ";" ) arrPathExt = Split( strPathExt, ";" ) ' Check if the command line argument contains a dot ' which would mean we wouldn't have to use PATHEXT blnHasExt = CBool( InStr( WScript.Arguments.Unnamed(0), "." ) > 0 ) If blnHasExt Then ' If an extension WAS specified, just search the PATH strExt = Mid( WScript.Arguments.Unnamed(0), InStrRev( WScript.Arguments.Unnamed(0), "." ) ) arrPathExt = Array( strExt ) strResult = FindWhich( WScript.Arguments.Unnamed(0) ) Else If IsArray( arrInt ) And Not blnExtOnly Then ' Let's check for INTERNAL commands first, unless of course, the /X switch was used For i = 0 To UBound( arrInt ) If UCase( WScript.Arguments.Unnamed(0) ) = arrInt(i) Then strResult = "[" & wshShell.ExpandEnvironmentStrings( "%COMSPEC%" ) & "]::" & arrInt(i) Exit For End If Next End If If strResult = "" Then strResult = FindWhich( WScript.Arguments.Unnamed(0) ) End If End If ' Copy the result to clipboard if the /C command line switch was used If blnClipboard Then Set objIE = CreateObject( "InternetExplorer.Application" ) objIE.Navigate( "about:blank" ) objIE.Document.ParentWindow.ClipboardData.SetData "text", strResult objIE.Quit Set objIE = Nothing End If ' Display the result, unless the /Q command line switch was used If Not blnQuiet Then WScript.Echo strResult End If ' Return code 1 if not found WScript.Quit -( strResult = "" ) Function FindWhich( myFile ) ' This function searches the directories in the PATH array for the ' specified file name, adding extensions from PATHEXT if required Dim i, j, objFound, strFound, strFullPath, strTestPath strFound = "" For i = 0 To UBound( arrPath ) ' Skip empty directory values, caused by the PATH ' variable being terminated with a semicolon If Trim( arrPath(i) ) <> "" Then ' Iterate through the array with extensions (if an extension was specified, ' the array will only contain the specified extension, otherwise it will ' contain all extensions in PATHEXT) For j = 0 To UBound( arrPathExt ) ' Build a fully qualified path of the file to test for strTestPath = objFSO.BuildPath( arrPath(i), objFSO.GetBaseName( myFile ) & arrPathExt(j) ) ' Check if that file exists If objFSO.FileExists( strTestPath ) Then Set objFound = objFSO.GetFile( strTestPath ) If blnVer Then strVer = objFSO.GetFileVersion( strTestPath ) If strVer = "" Then strVer = objFound.DateLastModified End If End If If blnShort Then ' Get the capitalization right strTestPath = objFSO.GetAbsolutePathName( strTestPath ) ' Return the short full path strFullPath = objFound.ShortPath Else ' Return the full path with proper capitalization strFullPath = objFSO.GetAbsolutePathName( strTestPath ) End If If blnAll Then ' Append the path of the file found strFound = strFound & strFullPath If blnVer Then strFound = strFound & vbTab & strVer strFound = strFound & ";" Else ' Abort when the first file is found strFound = strFullPath If blnVer Then strFound = strFound & vbTab & strVer Exit For End If Set objFound = Nothing ' Unless the /A (All) command line switch was used, abort inner loop after the first file is found If strFound <> "" And Not blnAll Then Exit For End If Next End If ' Unless the /A (All) command line switch was used, abort outer loop after the first file is found If strFound <> "" And Not blnAll Then Exit For Next If strFound <> "" Then arrFound = Split( strFound, ";" ) strFound = Join( arrFound, vbCrLf ) End If FindWhich = strFound End Function Sub Syntax( ) Dim strMsg strMsg = vbCrLf _ & "Which.vbs, Version 1.20" & vbCrLf _ & "Find out which file or internal command is actually executed when you type" _ & vbCrLf _ & "a command without its fully qualified path (like UNIX command, but extended)" _ & vbCrLf & vbCrLf _ & "Usage: WHICH.VBS filename[.ext] [ /A ] [ /C [ /Q ] ] [/S] [/V] [/X]" _ & vbCrLf & vbCrLf _ & "Where: filename[.ext] file name (with optional extension) or internal command" _ & vbCrLf _ & " to search for; wildcards (""*"" and ""?"") are not allowed;" _ & vbCrLf _ & " use the extension to search for .dll, .ocx, .ps1, etc." _ & vbCrLf _ & " /A list All matches, not just the first match" _ & vbCrLf _ & " /C copy result to the Clipboard" _ & vbCrLf _ & " /Q Quiet mode, no screen output (only valid with /C)" _ & vbCrLf _ & " /S return Short path(s) (8.3 notation)" _ & vbCrLf _ & " /V show Version number" _ & vbCrLf _ & " /X eXternal commands only, ignore internal commands" _ & vbCrLf & vbCrLf _ & "Notes: /A and /V switches will be ignored for internal commands" _ & vbCrLf _ & " /V will display file timestamp for non-executables" _ & vbCrLf & vbCrLf _ & "Written by Rob van der Woude" & vbCrLf _ & "http://www.robvanderwoude.com" & vbCrLf WScript.Echo strMsg WScript.Quit 1 End Sub
Note: | In NT batch files, the │ in the non-NT help is a vertical line extended ASCII character (character 179 in codepage 437).It is used because in non-NT Windows versions and in "real" DOS there is no way to escape a "real" pipe symbol. |
💾 Download sources for all UNIX ports
DOSKEY
macros and CMD
's internal commands.HEAD
and TAIL
replacements using Vincent Stahl's Swiss File Knifepage last modified: 2022-10-26; loaded in 0.0097 seconds