I Wrote A Batch Script to Enhance My Workflow on Command Prompt

I Wrote A Batch Script to Enhance My Workflow on Command Prompt

One Batch Script to Access All Your Existing Bash Aliases in WSL from within Windows Command Prompt

ยท

7 min read

Helllooo, everyone!

I just wrote a batch script! ( not bash script! )

Batch is the language in which scripts for windows command prompt(cmd.exe) are written.

What is special about this script?

That is what I going to discuss.

Summary of the Content Prior to Reading the Article

Dealing with custom Linux commands in Windows cmd or PowerShell can be a hassle. I created a batch script to run WSL commands, including functions and aliases, directly from cmd. This method avoids the complexity of replicating commands in Windows and enhances productivity by leveraging the convenience of WSL seamlessly within the Windows environment. The script assembles command-line arguments and executes them in an interactive Bash shell, speeding up workflows without the need for additional WSL or Git Bash instances.

Why I Needed The Script (AKA The Problem)

While WSL is a powerful tool for Windows users who want to leverage Linux commands and environment, it's often cumbersome to open the WSL terminal every time you want to run only one command, while you are actually working on powershell or command prompt.

I know what u will say now. You'll say, "Use the wsl cli bro, that's it!" But actually it's not just the cli that will always get you covered!

Suppose you are used to with some commands in your linux environment that are not any linux binary, they're some functions and aliases that are sourced when your shell is initialized.

For example this bash function (very convenient)

extract () {
    local file="$1";
    if [ -z "$file" ]; then
        printf "\033[1;31mNo file specified\n\033[0m" 1>&2;
        return 1;
    fi;
    if [ ! -f "$file" ]; then
        printf "\033[1;31mFile '%s' not found\n\033[0m" "$file" 1>&2;
        return 1;
    fi;
    local ext="${file#*.}";
    local extractor;
    local options="";
    case "$ext" in
        tar.bz2 | tbz2 | tar)
            extractor="tar";
            options="xvf"
        ;;
        tar.gz | tgz)
            extractor="tar";
            options="xzvf"
        ;;
        tar.xz)
            extractor="tar";
            options="Jxvf"
        ;;
        bz2)
            extractor="bunzip2"
        ;;
        rar)
            extractor="unar";
            options="-d"
        ;;
        gz)
            extractor="gunzip"
        ;;
        zip)
            extractor="unzip"
        ;;
        xz)
            extractor="unxz"
        ;;
        7z)
            extractor="7z";
            options="x"
        ;;
        Z)
            extractor="uncompress"
        ;;
        *)
            printf "\033[1;31mUnsupported file type: %s\n\033[0m" "$file" 1>&2;
            return 1
        ;;
    esac;
    if ! "$extractor" $options "$file"; then
        printf "\033[1;31mError extracting '%s'\n\033[0m" "$file" 1>&2;
        return 1;
    fi
}

I can extract any kind of (almost) archive file with this extract function, combining all necessary tool. One function to extract them all! This and one other function is in my .bash_functions file in my $HOME directory of WSL.

or these aliases -

alias gla='git log --oneline --graph --all'
alias la='exa -a --icons --group-directories-first' # exa needs to be preinstalled
alias ll='exa -alhF --icons' # exa needs to be preinstalled
alias cdf='cd $(fd -t d | fzf)' # fd-find and fzf needs to be preinstalled 
alias fvim='nvim $(fzf --preview="bat --color=always {}" --bind shift-up:preview-page-up,shift-down:preview-page-down)' # nvim, bat and fzf needs to be preinstalled
alias ff='fzf --preview=less --bind shift-up:preview-page-up,shift-down:preview-page-down)' # fzf and less needs to be preinstalled

These are the most notable aliases of mine ( I guess so ), which exist in the .bash_aliases of my $HOME directory of WSL.

The wsl cli is great for running linux binaries installed in the WSL system, outside the linux environment(WSL) for example in command prompt.

But none of provided options can make you run a custom command outside it.

What I Tried (AKA The Solution)

1st Approach

I thought, "Let's try to replicate the commands in windows..." But soon I realized that this is highly inconvenient because though powershell has better syntax and configuration option, although it has functions that almost written the same way as in bash, replicating the custom commands( those functions and aliases ) is going to be really difficult & it would need to install the required softwares in windows.

And for cmd, just don't even think about it. Also powershell and cmd doesn't support aliases like bash/zsh. Lastly, I couldn't find any init script like .bashrc for command prompt (probably no such thing exists, if does then please let me know).

Now you may again say, "Hey if you want aliases, why just not use doskey in cmd?" Again, DOSKEY is another highly inconvenient invention of windows devs. It is a command that can make macros for the interactive cli. It is inconvenient Because -

  • The DOSKEY macros cannot be used on either side of a pipe: Both someMacro|findstr '^' and dir|someMacro fail.

  • They cannot be used within a FOR /F commands: for /f %A in ('someMacro') do ... fails.

  • Macros written with DOSKEY, must be wrapped with % ( e.g. - if the name of the macro is grep then I would need to run it as %grep% ). For more info refer to this StackExchange answer.

    %[superuser.com/questions/560519/how-to-set-a..

So yeah I stopped there after researching about it.

2nd Approach

Here comes the good part. I realized, replicating commands will be waste of time. So let me try some way I can access every single command of the wsl I have, in command prompt working the exact same way. If there is no init script, I must make a command which can execute the bash functions and aliases along with all binaries.

So, I decided to write a batch script.

Why not powershell script?

Because powershell is slower than cmd. Even if it will be easier to write the script in powershell, as long as I know I need to write only 1 script & probably only 1 function, I think writing script for cmd is worth the try. And, along the way I will learn something new! Yoohoo!

Steps

  1. Created a directory 'bin' in my user home directory. Added the path to bin in the environment variables.

  2. Created a file runbash.bat inside bin. This will be the script.

  3. The syntax of batch is otherworldly to me. Hold on. Let's see the code of the script step by step. I am trying to explain the best I can.

  4. 1st line - @echo off. It will prevent command output from cluttering the console, while the script runs.

  5. 2nd line - setlocal enabledelayedexpansion. This is for handling variables dynamically within loops. It enables delayed expansion, which allows the use of variables within the same command line (using !VAR! instead of %VAR%).

  6. set CMDLINE= initializes an empty variable named CMDLINE, which will be used to accumulate the command line arguments.

  7. :loop marks the beginning of a loop.

  8. if "%~1"=="" goto end checks if the first argument (%~1) is empty. If it is, the script jumps to the :end label and stops processing arguments.

  9. set CMDLINE=!CMDLINE! %~1 appends the current argument (%~1) to the CMDLINE variable, building the command line.

  10. shift shifts the command line arguments to the left, so %2 becomes %1, %3 becomes %2, and so on. This effectively removes the first argument and allows the loop to process the next one.

  11. goto loop repeats the loop to process the next argument.

  12. :end: marks the end of the loop, where all arguments have been processed.

  13. bash -ic "!CMDLINE!" executes the accumulated command (CMDLINE) in the default Bash shell, which the bash of the default wsl using the -i (interactive) option to ensure it runs in an interactive shell. The -c option tells Bash to execute the command string.

Finally the script would be this.

The Script

@echo off
setlocal enabledelayedexpansion
set CMDLINE=
:loop
if "%~1"=="" goto end
set CMDLINE=!CMDLINE! %~1
shift
goto loop
:end
bash -ic "!CMDLINE!"

So, that's it! Now i have a new command in my Windows environment which enables me to run any custom command in my WSL environment right within cmd! How cool is that! Look at that, works like a charm!

successfully run the bash alias outside wsl

Final thoughts

So the second approach was actually a good decision. I saved a lot of time and effort.

Now this command turbocharges my productivity.

Also, my default wsl distro is Void linux, not Ubuntu. So the bash shell initialization doesn't take much time and all the commands work really fast with runbash.

Also the bonus is I don't need to open a separate git-bash instance or wsl to just run some bash files. I can write bash on windows and can execute them from the command prompt without opening wsl.

Running the basic bash script of eldenring from NetworkChuck's bash tutorial

If you found this POST helpful, if this blog added some value to your time and energy, please show some love by giving the article some likes and share it with your friends.

Feel free to connect with me at - Twitter, LinkedIn or GitHub :)

Happy Coding ๐Ÿง‘๐Ÿฝโ€๐Ÿ’ป๐Ÿ‘ฉ๐Ÿฝโ€๐Ÿ’ป! Have a nice day ahead! ๐Ÿš€

Did you find this article valuable?

Support Debajyati's Blogs by becoming a sponsor. Any amount is appreciated!

ย