A good Windows console environment

Sometimes I really miss the Linux shell on my Windows computers. I rely on too much Windows-specific stuff to actually switch to Linux for my everyday computing activities - not to mention Windows Phone development - but I do want more power from my commandline than cmd.exe provides by itself. I've customized my console experience pretty heavily on my Windows 8 laptop, and I'm pretty happy with it now. This post is both to help others do the same if they so wish, and to help me remember what I did for next time.

I've made some, shall we say, odd choices in this configuration, and I'll explain why along the way.

First of all, here's all that needs to be installed:

For simplicity's sake, I installed Cygwin in C:\Cygwin. Everything else was installed in default locations.

By default, ConEmu's installer enables the "Inject ConEmuHk" option for better compatibility. I found that it's pretty slow, so I disabled it.

After the above apps have been installed, comes the configuration.

In order to somewhat streamline the ConEmu configuration, I created a regular batch file that ConEmu launches both for a regular shell and for a "start in this directory" style shell. For the latter, I also created a shell script that takes care of going to the correct path when a file is selected instead of a directory. Here they are:

C:\Cygwin\constart.bat

@echo off  
C:\Cygwin\bin\screen.exe C:\Cygwin\bin\bash.exe -l -i %*

C:\Cygwin\conhere.sh

#!/bin/sh  
if [ -d "$1" ]; then  
    cd "$1"  
else  
    cd "`dirname \"$1\"`"  
fi  
bash  

That %* parameter in the batch file passes all commandline arguments given to the batch file onto Bash.

The reason I launch screen instead of launching Bash directly is a bit complicated. It's done in order to avoid a strange issue that causes Ctrl-C to not function when executing native Windows apps, such as ping. There are mailing list emails (one, two) that somewhat explain this bug and claim that it's fixed, respectively. However, it's not fixed for me. So, in order to use /dev/pty# instead of /dev/cons# through a regular shell, I'm cheating and launching it in screen, which is a virtual console. If there's a better way to do this, I'd really like to know.

ConEmu's startup commandline in its settings screen, under Startup, is:

C:\Cygwin\constart.bat -new_console:an

The -new_console parameter is interpreted by ConEmu itself; see its documentation for details.

Under Features/Integration, I configured the "ConEmu Here" context menu integration to the following command:

/single /cmd c:\cygwin\constart.bat -c "/conhere.sh \"`cygpath -u '%L'`\"" -new_console:an

Yes, that is one confusing command with lots of varying quotes. If there's an easier one, please tell me. Essentially, it launches Bash and makes it go to the current directory, signified by '%L'. It's in single quotes in order to handle spaces in directory names. The cygpath command is used to translate the Windows directory name to the Cygwin equivalent. The escaped double quotes surrounding that command are also for handling spaces in directory names. Finally, Bash is launched in interactive mode on the last line of conhere.sh instead of just quitting after changing directories.

Past all that, everything comes down to personal choices of Bash customization with functions, aliases, and so forth.

I disabled screen's Ctrl-A hook by adding the line "bind ^a" to /etc/screenrc. That turns screen into, for all intents and purposes, a regular virtual console.

Since nano has strange cursor scrolling behavior in Cygwin, I'm using ne instead. It's nice, and it comes with a binary specifically compiled for Cygwin.

For git and hg integration, I created functions in the global bashrc file for changing the $PS1 variable:

# Enable Hg integration  
__hg_ps1() {  
    hg prompt "{ on {branch}}{ at {bookmark}}{status}" 2> /dev/null  
}  
# Enable Git integration  
source /cygdrive/c/Program\ Files\ \(x86\)/Git/etc/git-completion.bash  
ps1def() {  
    export PS1='\[\e]0;\w\a\]\n\[\e[32m\]\u@\h \[\e[33m\]\w\[\e[0m\]\n\$ '  
}  
ps1hg() {  
    export PS1='\[\e]0;\w\a\]\n\[\e[32m\]\u@\h \[\e[33m\]\w\[\e[36m\]$(__hg_ps1)\[\e[0m\]\n\$ '  
}  
ps1git() {  
    export PS1='\[\e]0;\w\a\]\n\[\e[32m\]\u@\h \[\e[33m\]\w\[\e[36m\]$(__git_ps1)\[\e[0m\]\n\$ '  
}  
  
# Set a default prompt of: user@host current_directory {hg/git/none}  
ps1hg

The hg integration requires installation of hg-prompt and Python to run it.

Finally, I added some convenient aliases:

alias ls='ls --color=auto'  
alias la='ls -lha'  
alias 2w='cygpath -w'  
alias 2u='cygpath -au'  
alias nano='echo "Using ne instead of nano!"; sleep 2s; ne'

That's about it. I might be missing a few things, but for the most part, this is a very usable console environment that's better than the default Windows one. If you have any suggestions for improvement, I gladly welcome them.

 
comments powered by Disqus