, , , , , , , , ,

I have been using the command line more and more these days to get my work done. I have also been getting into Linux, or at least the Ubuntu distro of Linux. As a result I have been exposed to the ‘unix’ command line and have been enjoying it. So, I thought it was time to see how much ‘unix’ I could bring back over to my daily grind in Windows and I discovered cygwin.

In this post I am going to walk through the basics of installing and setting up the basics of cygwin.

Useful Tools

I will be using the following tools in this post as I have found that they make my life a little bit easier:

  • ConEmu: This is a great command line console for Windows
  • Chocolatey: Like apt-get for Ubuntu, Chocolatey is a package manager for Windows

So let’s get started.

Install cygwin using NuGet

  • Load up a command windows, for example ConEmu and install cygwin via Chocolatey. If you don’t have Chocolatey setup, it is quite simple. Checkout the installation instructions on their site
cinst cygwin
  • Run the setup program, by default Chocolatey will install cygwin here:

Set your ‘HOME’ directory

  • Add a user environment variable named ‘HOME’ to your windows user root directory

This makes the home directory of cygwin the same as your windows user home directory instead of the home directory inside the cygwin installation folder. You don’t need to do this but I find I like keeping all my settings in the same place.

  • If you want to be able to execute cygwin unix commands from the windows command prompt directly, you will need to add the cygwin bin directory to your system path. The default installation folder is:

Useful Cygwin Packages

Here is a list of the packages that I have installed at this time, and the reasons why I find them useful.

  • ncurses: gives you the ‘clear’ command. I’m sure it gives you more than that but that’s why I installed it.
  • vim: because vim.
  • ncftp: an improved ftp client (allows to easily download & upload entire directories)
  • dos2unix: This is a line break conversion utility that allows you to convert windows files to unix format. I needed this to load up my existing .vimrc & vim plugins.

Changing the cygwin mount

In cygwin, to navigate around your drives there is a default mount called ‘cygdrive’ that must be included to switch drives or navigate to a folder using a fully qualified location. For example, if I wanted to witch to say my ‘D’ drive I could do this:

cd /cygdrive/d

If I wanted to navigate to the ‘etc’ folder in the cygwin installation folder I could do this:

cd /cygdrive/c/cygwin/etc

I find the mount name ‘cygdrive’ quite long, so let’s change it! Since we are now in the ‘etc’ folder of the cygwin installation folder, open the ‘fstab’ file in your favourite text editor (I’ll use vim). You should see something like the following:

# For a description of the file format, see the Users Guide
# http://cygwin.com/cygwin-ug-net/using.html#mount-table

# This is default anyway:
none /cygdrive cygdrive binary,posix=0,user 0 0

All you need to do to change the ‘/cygdrive’ to ‘/whatever-you-want’. I like use use ‘root’ myself. Here is my updated fstab file

# For a description of the file format, see the Users Guide
# http://cygwin.com/cygwin-ug-net/using.html#mount-table

# This is default anyway:
none /root cygdrive binary,posix=0,user,noacl 0 0

Also, I discovered that it is quite important to add the “,noacl” to this command as well. This is because without it cygwin will see all files as read-only. Check out this article for more detail.

Now you can navigate around with less characters! Here is the previous example with the new mount name.

cd /root/d
cd /root/c/cygwin/etc

Configure Bash

Make a copy of the .bash_profile & .bashrc template files and place them in your HOME directory. The bash template files are located in the C:\\etc\skel directory.

These files give you a starting point for your bash configuration. They do have a few interesting examples in them, so read them though. Feel free to modify them to whatever works best for you.

The .bash_profile file is automatically loaded by bash when you start the cygwin console. As far as I know, this file also must be located in your HOME directory. Because of this, I have modified this file to do only one thing, load up the .bashrc file that I locate in my OneDrive. My OneDrive might be located in different places on each machine so I have created an environment variable for it called OneDriveDir. This way my actual bash settings can be synchronized between all my machines. Here is a sample of my .bash_profile. If you are storing your files in the home directory, use the HOME environment variable instead.

# source the users bashrc if it exists
if [ -f "${OneDriveDir}/Code/ide-settings/.dotfiles/.bashrc" ] ; then
  source "${OneDriveDir}/Code/ide-settings/.dotfiles/.bashrc"

Now we are going to do something similar with the .bashrc file. I like to keep my aliases and functions in their own files, for maintainability. I create a .bash_aliases & a .bash_functions file along side my .bashrc. You can create files in cygwin with the touch command

touch .bash_aliases
touch .bash_functions

So, in the .bashrc file I once again just source in these files. I also left in a couple other lines from the template that I thought looked useful. I moved all the aliases & functions into the new files and then deleted all the rest for clarity. Here is my current .bashrc file.

# If not running interactively, don't do anything
[[ "$-" != *i* ]] && return

source "${OneDriveDir}/Code/ide-settings/.dotfiles/source/command_prompt.sh"

# History Options
# Don't put duplicate lines in the history.

# Aliases
if [ -f "${OneDriveDir}/Code/ide-settings/.dotfiles/.bash_aliases" ]; then
  source "${OneDriveDir}/Code/ide-settings/.dotfiles/.bash_aliases"

# Functions
if [ -f "${OneDriveDir}/Code/ide-settings/.dotfiles/.bash_functions" ]; then
  source "${OneDriveDir}/Code/ide-settings/.dotfiles/.bash_functions"

Here is my .bash_functions file:

# This function defines a 'cd' replacement function capable of keeping, 
# displaying and accessing history of visited directories, up to 10 entries.
# To use it, uncomment it, source this file and try 'cd --'.
# acd_func 1.0.5, 10-nov-2004
# Petar Marinov, http:/geocities.com/h2428, this is public domain
cd_func ()
  local x2 the_new_dir adir index
  local -i cnt

  if [[ $1 ==  "--" ]]; then
    dirs -v
    return 0

  [[ -z $1 ]] && the_new_dir=$HOME

  if [[ ${the_new_dir:0:1} == '-' ]]; then
    # Extract dir N from dirs
    [[ -z $index ]] && index=1
    adir=$(dirs +$index)
    [[ -z $adir ]] && return 1

  # '~' has to be substituted by ${HOME}
  [[ ${the_new_dir:0:1} == '~' ]] && the_new_dir="${HOME}${the_new_dir:1}"

  # Now change to the new dir and add to the top of the stack
  pushd "${the_new_dir}" > /dev/null
  [[ $? -ne 0 ]] && return 1

  # Trim down everything beyond 11th entry
  popd -n +11 2>/dev/null 1>/dev/null

  # Remove any other occurence of this dir, skipping the top of the stack
  for ((cnt=1; cnt /dev/null)
    [[ $? -ne 0 ]] && return 0
    [[ ${x2:0:1} == '~' ]] && x2="${HOME}${x2:1}"
    if [[ "${x2}" == "${the_new_dir}" ]]; then
      popd -n +$cnt 2>/dev/null 1>/dev/null

  return 0

alias cd=cd_func

And finally my .bash_aliases file:

# Mics
alias less='less -r'
alias grep='grep --color'

# directory listing
alias ls='ls -hF --color=tty'       # classify files in colour
alias ll='ls -l'            # long list
alias la='ls -A'            # all but . and ..
alias l='ls -CF'

# directory shortcuts
alias cloud='cd "$OneDriveDir"'

# edit shortcuts
alias bashrc='vim "$OneDriveDir/Code/ide-settings/.dotfiles/.bashrc"'
alias bashalias='vim "$OneDriveDir/Code/ide-settings/.dotfiles/.bash_aliases"'
alias bashfunc='vim "$OneDriveDir/Code/ide-settings/.dotfiles/.bash_functions"'

As you can see I picked out some of the default aliases from the template that I found useful as well as added a few navigational & edit shortcuts. I’m sure this file will grow over time.

In Closing

This is my current setup and I’m sure it will evolve over time. I hope it has helped you out in some small way.