enhancement to cmd.exe

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Post Reply
Message
Author
siberia-man
Posts: 208
Joined: 26 Dec 2013 09:28
Contact:

enhancement to cmd.exe

#1 Post by siberia-man » 25 Mar 2016 04:00

In real life I prefer using more powerful and flexible tools like Clink, ConEmu and Far. But it was so fun to develop this script. Once executing the script setcmd.bat you will get more benefits working under cmd.exe.

Mod edit #2: Just a note to say that this has an install feature to modify your registry, to auto-load this script in the future. It can be uninstalled in a similar way to undo this feature. By default, it doesn't install itself permanently.

============

ALIASES

First of all it declares the following builtin aliases (doskey macros)

alias
show all aliases

alias name=text
assign name for the commands

alias -r [FILENAME]
read a file FILENAME or %CMD_ALIASFILE% and load new list of aliases

unalias name
remove alias by name

history
show the history of the current session

history -c
clear the current history of commands

history -w
write (append) the current history ot the file defined in %CMD_HISTFILE%

cd [path]
show the current directory or proceed to the directory path

cd -
return to the previously visited directory

cd ~
proceed to the %USERPROFILE% directory

exit, CTRL-D
write the history to the file history file and finish the current cmd.exe session. Pressing CTRL-D buttions should be ended by pressing the ENTER button.

============

ENVIRONMENT

CMD_SETCMDDIR
Points to the directory where the main script setcmd.bat is located

CMD_ALIASFILE
Define the name of the file of aliases or DOSKEY macros.

CMD_ALIAS_NOBUILTINS
Any non-empty value disables setting of builtin aliases at startup.

CMD_HISTFILE
Define the name of the file in which command history is saved.

CMD_HISTFILESIZE
Define the maximum number of lines in the history file.

CMD_HISTSIZE
Define the maximum number of commands remembered by the buffer. By default DOSKEY stores 50 latest commands in its buffer.

User file
Putting setcmd.rc.bat file to CMD_SETCMDDIR, HOME or USERPROFILE directory you can change behavior of the main script. You can define some variables (for example set PATH etc) or re-declare the variables from the list above.

============

AUTORUN

Run the script once for automate its execution when cmd.exe launching:

Code: Select all

setcmd autorun -i


Run the following command to uninstall the script

Code: Select all

setcmd autorun -u


In this case (only this case!) the script modifies the Window Registry node "HKCU\Software\Microsoft\Command Processor" to autoload the script. This has been developed to give to the end user the choice how to use the script.

============

SOURCE CODE
The actual version of the script is here: https://github.com/ildar-shaimordanov/c ... setcmd.bat
Example of aliases file is here: https://github.com/ildar-shaimordanov/c ... md.aliases

Code: Select all

::
:: The tool was developed to enhance the functionality of `cmd.exe`
:: similar to Unix-like shells. It is completely written as batch script
:: and does npt add any external binaries. Nevertheless, it gives more
:: functions and flexibility to `cmd.exe` and do maintainance little bit
:: easier.
::
:: In fact, this script is weak attempt to be closer to other shells -
:: powerful, flexible and full-functional ones. Nevertheless, it works!
:: This script can be found useful for those folks, who are not permitted
:: to setup any other binaries excepting those applications permitted for
:: installation. The better way is to use the other solutions like
:: `Clink`, `ConEmu` or something else.
::
@echo off

for %%1 in (

   "help"
   "alias.readfile"
   "history"
   "cd"
   "autorun"

) do if /i "%~1" == "%%~1" (
   call :cmd.%*
   goto :EOF
)

if not "%~1" == "" (
   >&2 echo:Unknown command "%~1".
   goto :EOF
)


::
:: # USER DEFINED FILE
::
::
:: The user defined file `setcmd.rc.bat` allows to customize the user's
:: environment. Firstly, it is checked for existance in the same directory
:: where `setcmd.bat` is located, further it is checked under the `HOME`
:: directory and finally under the user's profile. If these files exist
:: they are called and affects on the further execution. Each of them can
:: override previous settings.
::
:: This behavior is very close to the existing in unix world when settings
:: of `~/.bashrc` override settings of `/etc/bashrc`.
::
:: The `CMD_SETCMDDIR` environment variable points to the directory where
:: the main script `setcmd.bat` is located. It can be used, if some
:: settings are placed under this directory.
::
for /f "tokens=*" %%f in ( "%~dp0." ) do set "CMD_SETCMDDIR=%%~ff"

if exist "%~dpn0.rc.bat" call "%~dpn0.rc.bat"
if exist "%HOME%\%~n0.rc.bat" call "%HOME%\%~n0.rc.bat"
if exist "%USERPROFILE%\%~n0.rc.bat" call "%USERPROFILE%\%~n0.rc.bat"


::
:: # ENVIRONMENT VARIABLES
::
::
:: Behaviour of the script depends on some environment variables described
:: below. Most of them have synonyms in unix and the same meaning.
::
:: Uncomment a line if you want to turn on a feature supported by a
:: variable. The better place for tuning all these variables is auxiliary
:: `setcmd.rc.bat` script (see the description above).
::
::
:: `CMD_ALIASFILE`
::
:: Define the name of the file of aliases or `DOSKEY` macros.
::
if not defined CMD_ALIASFILE set "CMD_ALIASFILE=%~dpn0.aliases"
::
:: `CMD_ALIAS_NOBUILTINS`
::
:: Any non-empty value disables setting of builtin aliases at startup.
::
rem if not defined CMD_ALIAS_NOBUILTINS set "CMD_ALIAS_NOBUILTINS=1"
::
:: `CMD_HISTFILE`
::
:: Define the name of the file in which command history is saved.
::
rem if not defined CMD_HISTFILE set "CMD_HISTFILE=%~dpn0.history"
::
:: `CMD_HISTFILESIZE`
::
:: Define the maximum number of lines in the history file.
::
rem if not defined CMD_HISTFILESIZE set /a "CMD_HISTFILESIZE=500"
::
:: `CMD_HISTSIZE`
::
:: Define the maximum number of commands remembered by the buffer.
:: By default `DOSKEY` stores `50` latest commands in its buffer.
::
rem if not defined CMD_HISTSIZE set /a "CMD_HISTSIZE=50"
::
:: `CMD_HISTCONTROL`
::
:: A semicolon-separated list of values controlling how commands are saved
:: in the history file.
::
:: **Not implemented**
::
rem if not defined CMD_HISTCONTROL set "CMD_HISTCONTROL="
::
:: `CMD_HISTIGNORE`
::
:: A semicolon-separated list of ignore patterns used to decide which
:: command lines should be saved in the history file.
::
:: **Not implemented**
::
rem if not defined CMD_HISTIGNORE set "CMD_HISTIGNORE="

if not defined CMD_ALIAS_NOBUILTINS call :cmd.alias.builtins
if exist "%CMD_ALIASFILE%" call :cmd.alias.readfile "%CMD_ALIASFILE%"

goto :EOF


:cmd.help
for /f "tokens=* delims=: " %%s in ( '
   findstr /b "::" "%~f0"
' ) do echo:%%~s
goto :EOF


:cmd.alias.builtins
::
:: # ALIASES
::
::
:: `alias`
::
:: Display all aliases.
::
::
:: `alias name=text`
::
:: Define an alias with the name for one or more commands.
::
::
:: `alias -r [FILENAME]`
::
:: Read aliases from the specified file or `CMD_ALIASFILE`.
::
doskey alias=^
if "$1" == "" ( doskey /macros ) else ^
if "$1" == "-r" ( "%~f0" alias.readfile "$2" ) else ( doskey $* )
::
:: `unalias name`
::
:: Remove the alias specified by name from the list of defined aliases.
:: Run `DOSKEY /?` for more details.
::
doskey unalias=doskey $1=
::
:: `history`
::
:: Display or manipulate the history list for the actual session.
:: Run `DOSKEY /?` for more details.
::
doskey history="%~f0" history $1
::
:: `cd`
::
:: Display or change working directory.
::
doskey cd="%~f0" cd $1
::
:: `exit`
::
:: Exit the current command prompt; before exiting store the actual
:: history list to the history file `CMD_HISTFILE` when it is configured.
::
doskey exit=if not "$1" == "/?" ( "%~f0" history -w ) $T exit $*
::
:: `CTRL-D`
::
:: `CTRL-D` (`ASCII 04`, `EOT` or the *diamond* symbol) is useful shortcut
:: for the `exit` command. Unlike Unix shells the `CTRL-D` keystroke
:: doesn't close window immediately. In Windows command prompt you need to
:: press the `ENTER` keystroke.
::
doskey ="%~f0" history -w $T exit
goto :EOF


::
:: # ALIAS FILE
::
::
:: Alias file is the simple text file defining aliases or macros in the
:: form `name=command` and can be loaded to the session by the prefedined
:: alias `alias -r`.
::
:cmd.alias.readfile
setlocal

if not "%~1" == "" set "CMD_ALIASFILE=%~1"

if not defined CMD_ALIASFILE (
   endlocal
   goto :EOF
)

if not exist "%CMD_ALIASFILE%" (
   >&2 echo:"%CMD_ALIASFILE%" not found.
   endlocal
   goto :EOF
)

set /a "CMD_HISTSIZE=CMD_HISTSIZE"
if %CMD_HISTSIZE% gtr 0 doskey /LISTSIZE="%CMD_HISTSIZE%"

doskey /MACROFILE="%CMD_ALIASFILE%"

endlocal
goto :EOF


::
:: # HISTORY
::
::
:: `history [options]`
::
::
:: ## Options
::
:cmd.history
if "%~1" == ""   goto :cmd.history.print
if "%~1" == "-c" goto :cmd.history.clear
if "%~1" == "-C" goto :cmd.history.uninstall
if "%~1" == "-w" goto :cmd.history.write

>&2 echo:Unsupported history option "%~1".
goto :EOF


::
:: `history`
::
:: Displays the history of the current session.
::
:cmd.history.print
doskey /HISTORY
goto :EOF


::
:: `history -c`
::
:: Clear the history list by setting the history size to 0 and reverting
:: to the value defined in `CMD_HISTSIZE` or `50`, the default value.
::
:cmd.history.clear
setlocal

set /a "CMD_HISTSIZE=CMD_HISTSIZE"
if %CMD_HISTSIZE% leq 0 set CMD_HISTSIZE=50
doskey /LISTSIZE=0
doskey /LISTSIZE=%CMD_HISTSIZE%

endlocal
goto :EOF


::
:: `history -C`
::
:: Install a new copy of `DOSKEY` and clear the history buffer. This way
:: is less reliable and deprecated in usage because of possible loss of
:: control over the command history.
::
:cmd.history.uninstall
doskey /REINSTALL
goto :EOF


::
:: `history -w`
::
:: Write the current history to the file `CMD_HISTFILE` if it is defined.
::
:cmd.history.write
if not defined CMD_HISTFILE goto :EOF

doskey /HISTORY >>"%CMD_HISTFILE%" || goto :EOF

if not defined CMD_HISTFILESIZE goto :EOF

setlocal

set /a "CMD_HISTFILESIZE=CMD_HISTFILESIZE"
set /a "CMD_FILEPOS=0"

for /f %%f in ( '
   "%windir%\System32\more.exe" ^< "%CMD_HISTFILE%" ^| ^
   "%windir%\System32\find.exe" /v /c ""
' ) do (
   set /a "CMD_FILEPOS=%%f-CMD_HISTFILESIZE"
)

if %CMD_FILEPOS% leq 0 (
   endlocal
   goto :EOF
)

more +%CMD_FILEPOS% "%CMD_HISTFILE%" >"%CMD_HISTFILE%~"
move /y "%CMD_HISTFILE%~" "%CMD_HISTFILE%"

endlocal
goto :EOF


::
:: # CHANGE DIRECTORY
::
::
:: `cd [options]`
::
::
:: Change the current directory can be performed by the following commands
:: `CD` or `CHDIR`. To change both current directory and drive the option
:: `/D` is required. To avoid certain typing of the option and simplify
:: navigation between the current directory, previous one and user's home
:: directory, the command is extended as follows.
::
:: See the following links for details
::
:: * http://ss64.com/nt/pushd.html
:: * http://ss64.com/nt/popd.html
:: * http://ss64.com/nt/cd.html
::
:: There is another way how to combine `cd`, `pushd` and `popd`. You can
:: find it following by the link:
::
:: * https://www.safaribooksonline.com/library/view/learning-the-bash/1565923472/ch04s05.html
::
::
:: `cd`
::
:: Display the current drive and directory.
::
::
:: `cd ~`
::
:: Change to the user's home directory.
::
::
:: `cd -`
::
:: Change to the previous directory. The previously visited directory is
:: stored in the OLDCD variable. If the variable is not defined, no action
:: happens.
::
::
:: `cd path`
::
:: Change to the directory cpecified by the parameter.
::
:cmd.cd
if "%~1" == "-" if not defined OLDCD (
   >&2 echo:OLDCD not set
   goto :EOF
)

if "%~1" == "" (
   cd
   goto :EOF
)

setlocal

if "%~1" == "-" (
   set "NEWCD=%OLDCD%"
) else if "%~1" == "~" (
   set "NEWCD=%USERPROFILE%"
) else (
   set "NEWCD=%~1"
)

endlocal & set "OLDCD=%CD%" & cd /d "%NEWCD%"
goto :EOF


:cmd.autorun
setlocal

set "CMD_AUTORUN=HKCU\Software\Microsoft\Command Processor"

if "%~1" == "-s" (
   reg query  "%CMD_AUTORUN%" /v "AutoRun"
) else if "%~1" == "-i" (
   reg add    "%CMD_AUTORUN%" /v "AutoRun" /t REG_EXPAND_SZ /d "\"%~f0\"" /f
) else if "%~1" == "-u" (
   reg delete "%CMD_AUTORUN%" /v "AutoRun" /f
) else (
   >&2 echo:Unsupported autorun option "%~1".
)

endlocal
goto :EOF


::
:: # ADDITIONAL REFERENCES
::
:: * https://msdn.microsoft.com/ru-ru/library/windows/desktop/ee872121%28v=vs.85%29.aspx
:: * http://www.outsidethebox.ms/12669/
:: * http://www.transl-gunsmoker.ru/2010/09/11.html
:: * http://habrahabr.ru/post/263105/
::
Last edited by siberia-man on 28 Mar 2016 00:12, edited 1 time in total.

siberia-man
Posts: 208
Joined: 26 Dec 2013 09:28
Contact:

Re: enhancement to cmd.exe

#2 Post by siberia-man » 28 Mar 2016 00:10

Mod edit wrote:Mod edit: Just a note to say that this modifies your registry to auto-load this script in the future. You will need to uninstall it to disable this feature.


That is true if someone would like to install it explicitly:

Code: Select all

setcmd.bat autorun -i


or uninstall it

Code: Select all

setcmd.bat autorun -u


In other cases the script do nothing in windows registry or on the file system. Even storing of commands history to a file is enable after explicit setting the name of the history file. I have updated the section AUTORUN above to be more precise.

Any comments are welcome :)

Post Reply