[ACCEPTED]-msys path conversion (or cygpath for msys?)-cygpath

Accepted answer
Score: 59

Update (Aug-2016):

This question is no longer relevant, as 28 msys2 now comes with cygpath in its installation.

...

I'll 27 summarize my research here.

The cygpath equivalent 26 in MSYS is to use this command:

{ cd /c/some/path && pwd -W; } | sed 's|/|\\|g'

The problem 25 with this approach is that it requires existing 24 path, e.g. the c:\some\path has to be an existing directory; however, real 23 cygpath supports paths that do not exist.

So, if 22 you need to get path to a directory that 21 doesn't exist, then you can fallback to 20 sed conversion of the path:

{ cd 2>/dev/null /c/some/path && pwd -W ||
  echo /c/some/path | sed 's|^/\([a-z,A-Z]\)/|\1:/|'; } | sed 's|/|\\|g'

The mouthful 19 of slashes is there to satisfy quoting rules 18 of sed. So, if c:\some\path doesn't exist on your PC, it 17 will try to convert forward to back slashes 16 and replace /c/ with c:\ (or any other drive letter). The 15 only drawback for this is that it won't 14 work correctly non-existing paths that contain 13 a mounted component, such as /bin/does-not-exist or /usr/bin/does-not-exist.

One more 12 approach is to use cygpath from cygwin in MSYS. It 11 seems that cygwin sets global environment 10 variable CYGPATH, that is, you can use it 9 from regular cmd.exe:

%CYGPATH% -w /c/some/path
C:\some\path

or from MSYS:

$CYGPATH -w /c/some/path
C:\some\path

as long 8 as you set to point /c to /cygdrive/c in cygwin. But 7 this approach will print you /usr located in 6 cygwin installation, not in MSYS.

In short, I 5 think msys should really include real cygpath 4 in the default set of tools just for some 3 cases that aren't handled automatically 2 by msys command line argument conversion 1 logic

Score: 14

use pwd -W

or download cygpath for msys from here 1 http://mingw.5.n7.nabble.com/enhanced-version-of-cygpath-td28556.html

and use cygpath -wa

Score: 8

Similar to dmitri-rubinstein@ above, I've 2 cleaned up the code a bit and added the 1 reverse conversion as well.

winpath() {
    if [ ${#} -eq 0 ]; then
        : skip
    elif [ -f "$1" ]; then
        local dirname=$(dirname "$1")
        local basename=$(basename "$1")
        echo "$(cd "$dirname" && pwd -W)/$basename" \
        | sed \
          -e 's|/|\\|g';
    elif [ -d "$1" ]; then
        echo "$(cd "$1" && pwd -W)" \
        | sed \
          -e 's|/|\\|g';
    else
        echo "$1" \
        | sed \
          -e 's|^/\(.\)/|\1:\\|g' \
          -e 's|/|\\|g'
    fi
}

unixpath() {
    echo "$1" \
    | sed -r \
      -e 's/\\/\//g' \
      -e 's/^([^:]+):/\/\1/'
}
Score: 6

I am using this with msysgit:

winpath() {
    if [ -z "$1" ]; then
        echo "$@"
    else
        if [ -f "$1" ]; then
            local dir=$(dirname "$1")
            local fn=$(basename "$1")
            echo "$(cd "$dir"; echo "$(pwd -W)/$fn")" | sed 's|/|\\|g';
        else
            if [ -d "$1" ]; then
                echo "$(cd "$1"; pwd -W)" | sed 's|/|\\|g';
            else
                echo "$1" | sed 's|^/\(.\)/|\1:\\|g; s|/|\\|g';
            fi
        fi
    fi
}

0

Score: 3

My bash foo is weak and I couldn't get regexes 2 working in bash 3.1 so I hacked out a perl 1 script for it:

#!/bin/env perl
use strict;

my @r;
foreach my $e (@ARGV) {
 $e=~s/\//\\/g;
 $e=~s/^\\([A-Za-z])\\/\1:\\/;
 push @r, $e;
}

print join(" ", @r);
Score: 3

MSYS cygpath

Program

This program convert a DOS path to a UNIX 6 path and vice versa

#!/bin/env perl
# DOS to UNIX path conversion
# © John S. Peterson. License GNU GPL 3.
use strict;
use Getopt::Std;

# usage
if ($#ARGV == -1) {
    print 'Usage: cygpath (-w) NAME...

Convert Unix and Windows format paths

Output type options:

  -w, --windows         print Windows form of NAMEs (C:\WINNT)
';
    exit 0;
}

# option
my %opt;
getopts('w', \%opt);

# convert path
my @r;
foreach my $e (@ARGV) {
    if ($opt{w}) {
        # add drive letter suffix
        $e =~ s,^\/([A-Za-z])\/,\1:\/,;
        $e =~ s,\/,\\,g;

    } else {
        $e =~ s,\\,\/,g;
        # add leading slash
        $e = "/$e";
        # remove drive letter suffix
        $e =~ s,:,,;
    }

    push @r, $e;
}

print join("\n", @r);

Compared to Cygwin cygpath

The output from this 5 program is better than the output from Cygwin 4 cygpath in MSYS because

  • Cygwin cygpath remove the Cygwin home from a converted path, f.e.
cygpath "$CYGWIN/usr/local/bin"
/usr/local/bin

which is a problem because

  • it's sometimes useful to convert a DOS Cygwin path to a UNIX path for the purpose of copying files from Cygwin to MSYS

This 3 program doesn't remove the Cygwin home

cygpath "$CYGWIN/usr/local/bin"
/c/file/program/cygwin/usr/local/bin

Compared to automatic MSYS path conversion

Manual 2 path conversion has a use in MSYS because

  • the automatic path conversion is inadequate

for 1 f.e.

Score: 3

How about this one ? cmd //c echo <your path>

It may not work always 1 but it is the shortest I found

Score: 0

This works for me

df "$1" | tac >k
read b <k
rm k
set "$1" $b
echo ${1/$7/$2/}

ref

0

Score: 0

nearly pure GNU bash solution (which is what you 10 commonly run in MSYS) (interestingly not 9 working with MSYS2, leave a comment if you 8 know why):

#!/bin/bash

# check if we have cygpath (cygwin, newer MSYS2), then just use that 
which cygpath 1>/dev/null 2>&1
[[ $? = 0 ]] && (cygpath -wa "$1"; exit $?)

# check if it looks like a Windows path, in which case we directly convert and exit
[[ ${1} =~ ^[a-zA-Z]: ]] && \
  echo "${1}" | sed -e 's|/|\\|g' -e 's/\(.\)/\u\1/' && exit 0

# split first path entry (if any) with trailing slash and filename
[[ ${1} =~ ^\([/a-zA-Z0-9_.-]\\w*/\)?\(.*\)$ ]]

chk_root="${BASH_REMATCH[1]}"
chk_rest="${BASH_REMATCH[2]}"

# check if the root path exists and more important: let pwd binary resolve the translation according to the mount
chk_winroot="$(cd "${chk_root}." 2>/dev/null && pwd -W)"
[[ "${chk_winroot}" == "" ]] && echo "${chk_root}: No such file or directory" && exit 1

# using substition to replace all / by \ and uppercasing the first character
# pure bash solution; sadly: the first part needs a newer bash than old MSYS have ...
# chk_drv="${chk_winroot:0:1}"
# chk_all="${chk_winroot:1}/${chk_rest}"
# echo "${chk_drv^^}${chk_all//\//\\}"

# ... so fallback to GNU sed
echo "${chk_winroot}/${chk_rest}" | sed -e 's|/|\\|g' -e 's/\(.\)/\u\1/'

There's still an issue with it: if 7 MinGW's fstab contains an entry like /mnt/c the 6 pwd -W of /mnt/. done in this script won't work.
To 5 fix it: replace pwd -W by inspecting $ cat /etc/fstab | cut -d'#' -f1 | grep -v "^\s*$" entries 4 manually and replace the first match - while 3 this will never work for cygwin or msys2 2 which use a different format this is covered 1 by using cygpath there.

More Related questions