Cygwin paths and perlbrew
I’ve been messing around with perlbrew lately and decided to give it a whirl on Cygwin. Right off the bat I ran into a problem with my $PATH.
PATH=/usr/local/bin:/usr/bin:/usr/local/bin:/usr/bin:/cygdrive/c/Program Files/Common Files/Microsoft Shared/Windows Live:/cygdrive/c/Program Files (x86)/Common Files/Microsoft Shared/Windows Live:/cygdrive/c/Program Files (x86)/AMD APP/bin/x86_64:/cygdrive/c/Program Files (x86)/AMD APP/bin/x86:/cygdrive/c/Windows/system32:/cygdrive/c/Windows:/cygdrive/c/Windows/System32/Wbem:/cygdrive/c/Windows/System32/WindowsPowerShell/v1.0:/cygdrive/c/Program Files/Intel/WiFi/bin:/cygdrive/c/Program Files/Common Files/Intel/WirelessCommon:/cygdrive/c/Program Files (x86)/ATI Technologies/ATI.ACE/Core-Static:/cygdrive/c/Program Files (x86)/Intel/Services/IPT:/cygdrive/c/Program Files (x86)/Symantec/VIP Access Client:/cygdrive/c/Program Files (x86)/Sony/VAIO Startup Setting Tool:/cygdrive/c/Program Files (x86)/Common Files/Roxio Shared/10.0/DLLShared:/cygdrive/c/Program Files (x86)/Common Files/Roxio Shared/DLLShared:/cygdrive/c/Program Files (x86)/Windows Live/Shared
Spaces everywhere, which the perl installer did not take kindly to.
I had two options at this point:
- Set $PATH to only include what was needed to install and be done with it
- Spend a good chunk of time Googling how to convert the paths to something perl wouldn’t complain about.
I of course, took option 2.
I wanted my default paths to work with whatever I needed to do. $PATH is given to Cygwin by Windows, so I’d like to keep it that way for consistency. The necessity of doing this can be debated.
I needed:
/cygdrive/c/Program Files/Common Files/Microsoft Shared/Windows Live
to become:
/cygdrive/c/PROGRA~1/COMMON~1/MICROS~1/WINDOW~1
cygpath
I found cygpath and thought it would be all I needed.
I was wrong.
The command has options to display unix style paths, windows style paths and short paths, but it does not allow you to combine the short style with the unix style.
Unix Style Path:
/cygdrive/c/Program Files/Common Files/Microsoft Shared/Windows Live
Mixed Style Path:
$ cygpath -m "/cygdrive/c/Program Files/Common Files/Microsoft Shared/Windows Live"
C:/Program Files/Common Files/Microsoft Shared/Windows Live
Short Style Path:
$ cygpath -m -s "/cygdrive/c/Program Files/Common Files/Microsoft Shared/Windows Live"
C:/PROGRA~1/COMMON~1/MICROS~1/WINDOW~1
Fixing $PATH
I would need to create a shell script to combine the mixed and short style paths into something I could use.
# First we need to split $PATH
# on ':' and put each line into
# an array
OLD_IFS=$IFS
IFS=$'\n'
paths=(`echo $PATH | tr -s ":" "\n"`)
IFS=$OLD_IFS
# The paths supplied from Windows
# may not actually exist. These
# paths will cause cygpath to error
# so we will skip them and only
# process actual directories.
valid_paths=();
for path in "${paths[@]}"; do
if [ -d "${path}" ]; then
# Save the cygdrive we are parsing
cygdrive_save=$(echo $path | grep -oEi "/cygdrive/[a-z]+")
if [[ $cygdrive_save ]]; then
# Get the short version of the path from cygpath
# We can't have ':' in our path so only grab the
# path following C: (or other drive letter)
no_space_path=$(cygpath -a -m -s "${path}" | cut -d : -f 2);
# Use the saved cygdrive from above and
# prepend it to the short path
valid_paths=("${valid_paths[@]}" "${cygdrive_save}${no_space_path}")
else
valid_paths=("${valid_paths[@]}" $path)
fi
fi
done
# Join the valid_paths array with ':'
# and set $PATH
OLD_IFS=$IFS
IFS=":"
PATH="${valid_paths[*]}"
IFS=$OLD_IFS
Add to .bash_profile and now my $PATH looks like this:
$ printenv PATH
/home/Kevin/perl5/perlbrew/bin:/usr/local/bin:/usr/bin:/usr/local/bin:/usr/bin:/cygdrive/c/PROGRA~1/COMMON~1/MICROS~1/WINDOW~1:/cygdrive/c/PROGRA~2/COMMON~1/MICROS~1/WINDOW~1:/cygdrive/c/PROGRA~2/AMDAPP~1/bin/x86_64:/cygdrive/c/Windows/system32:/cygdrive/c/Windows:/cygdrive/c/Windows/System32/Wbem:/cygdrive/c/Windows/System32/WINDOW~1/v1.0:/cygdrive/c/PROGRA~1/Intel/WiFi/bin:/cygdrive/c/PROGRA~1/COMMON~1/Intel/WIRELE~1:/cygdrive/c/PROGRA~2/ATITEC~1/ATI.ACE/CORE-S~1:/cygdrive/c/PROGRA~2/Intel/Services/IPT:/cygdrive/c/PROGRA~2/Symantec/VIPACC~1:/cygdrive/c/PROGRA~2/Sony/VAIOST~1:/cygdrive/c/PROGRA~2/COMMON~1/ROXIOS~1/10.0/DLLSHA~1:/cygdrive/c/PROGRA~2/COMMON~1/ROXIOS~1/DLLSHA~1:/cygdrive/c/PROGRA~2/WIC4A1~1/Shared
Now the Perl install (and anything else that is space sensitive) works:
$ perlbrew list
perl-5.14.2
$ perlbrew exec perl -v
perl-5.14.2
==========
This is perl 5, version 14, subversion 2 (v5.14.2) built for cygwin-thread-multi-64int
Copyright 1987-2011, Larry Wall
Perl may be copied only under the terms of either the Artistic License or the
GNU General Public License, which may be found in the Perl 5 source kit.
Complete documentation for Perl, including FAQ lists, should be found on
this system using "man perl" or "perldoc perl". If you have access to the
Internet, point your browser at http://www.perl.org/, the Perl Home Page.
Shell scripting is not my strong suit. I’m guessing there is a better and possibly more efficient solution to this problem. I welcome any suggestions to clean it up.
