Making Cygwin and Windows cooperate

Cygwin uses a different path scheme than Windows. If you use a Cygwin shell with Cygwin programs, then everything works well. But if you use a Cygwin shell as your default shell (which I do, because face it, cmd.exe sucks) and you’re running non-Cygwin programs, you can run into trouble because the shell may send Cygwin-style paths for filenames to Windows programs that don’t understand them.

For instance today I was using a Cygwin bash shell with a non-Cygwin Perforce client (i.e.: “p4”).

$ p4 open foo.cpp 
Path '/cygdrive/c/dev/project/...\foo.cpp' is not under 
client's root 'C:\dev\project'.

p4 is a regular (non-Cygwin) program and thus it doesn’t understand the Cygwin path that gets sent to it.

One way to fix this would be to find a version of p4 that was compiled against Cygwin.

Another way is to use the cygpath command to convert the Cygwin path to a Windows path.

$ p4 open $(cygpath -aw foo.cpp) 
//depot/project/foo.cpp#2 - currently opened for edit

The -a option tells it to generate an absolute path and the -w option tells it to convert from a Cygwin path to a Windows path.

12 thoughts on “Making Cygwin and Windows cooperate

  1. I’ve used Cygwin/Windows daily now for several years, and have some helper scripts and aliases to help to translate paths for Windows applications.

    One common function is to translate a set of paths, as you describe above:

    for ((at=1; at <= $#; at++))
    do
        p="$p `cygpath -wa ${!at}`"
    done
    /cygdrive/c/Program\ Files/e/e.exe $p
    

    While not generic, it works well from the Cygwin/Bash shell. The above snip fails gracefully too, as cygpath ignores what it can’t translate. It’s also worth automating adding the Program\ Files path to your path (and its sub directories).

    FWIW, I’ve also found “Console2” to be a good Cmd.exe replacement (I think it actually wraps it somehow with anti-aliasing). Console2 is like gnome-terminal, less a few awkward key and mouse bindings, and can be used with the Cygwin/bash terminal. It’s the only replacement so far that works with all of my scripts, tools, and such (including reasonable termcap support).

  2. Oh, I should mention that I’ve found the “E editor” to be quite handy too (though a bit buggy still). It’s a Textmate clone for Windows, and it includes a Cygwin installation. I am looking forward to getting my teams to use it, as it makes the pain of Cygwin easier for most of the Window-ish devs.

  3. It’s nice to find others sharing tips for integrating Cygwin with other, non-Cygwin apps. I posted a similar tip earlier this year, for launching Textpad from Cygwin.

    Unfortunately, my bash function only supported passing one filename on the command-line (a limitation I openly admitted at the time, and blamed on sheer laziness).

    Now, using Bruce’s for loop (comment #1), I’ve changed my function to handle converting multiple Cygwin-style paths into the Windows-style paths that Textpad needs.

    Thanks, guys!

  4. I should note that there is a Cygwin version of p4, which I found at this page, which coincidentally has the same tip as me.

    You can copy the Cygwin p4.exe into C:cygwinbin and then use that, but it’s totally seamless, because if you were using the non-Cygwin P4, then your workspaces probably have Windows style paths in them and p4 will complain that your Cygwin paths do not reside in your workspace (the “is not under client’s root” error).

  5. The first solution requires far too much typing to use on a regular basis for a lazy programmer like myself. An extra “$(cygpath -wa path)” is too much.

    And looping through all the arguments won’t work either because some arguments are commands, others are switches. Also when setting up a remote machine, I want to make it work with minimum hassle.

    I think the simplest solution is to add the following to your .bashrc (sorry, I’m not sure how to make it fixed-font):

    function p4() {
    export PWD=`cygpath -wa .`
    /cygdrive/c/Program\ Files/Perforce/p4.exe $@
    }

  6. It’s better to quote the arguments:

    function p4() {
    export PWD=`cygpath -wa .`
    /cygdrive/c/Program\ Files/Perforce/p4.exe “$@”
    }

    That way it will also works with file with spaces in it.

  7. Thanks for the post!
    I added this in my ~/.profile:
    alias p=’cygpath -wa’
    so I can say:
    $(p filename)

  8. Another idea would be to use a script (called, winexec, say) that takes a windows command (eg: Notepad) and several arguments as an input.

    The script should do the following:
    1. For each path, detected by the beginning ‘/’, in the argument, run cygpath -aw on it.
    2. Now, execute the program supplied with the modified argument list.

    So, for example, winexec “/cygdrive/c/Windows/Notepad.exe” /cygdrive/c/boot.ini would essentially run “C:\Windows\Notepad.exe C:\boot.ini”

    Then, for each frequently used program (notepad, write, winword…), put an alias in bashrc which essentially calls “winexec /cygdrive/c/…/winword.exe” etc.

  9. Here’s my BASH script. Thanks to Bruce for showing me how to use a for loop. I’m sorry I’m not very good with BASH.

    #!/bin/bash
    # Execute a Windows program from Cygwin by appropriately tailoring the paths in the arguments
    convert=”cygpath -aw”

    argarray[0]=”$1″;

    for ((at=2; at <= $#; at++)); do
    index=$(($at-1))
    # echo -n "Index: $index; "
    # echo "Arg:" ${!at}"; "
    for path in `ls /`; do
    # echo "Path = /$path"
    if [[ ${!at} == /$path* ]]; then
    #This is most likely a cygwin path, convert it.
    argarray[$index]=`$convert ${!at}`
    # echo "Is a path. converted to ${argarray[$index]}"
    fi;
    done;
    if [ -n "${argarray[$index]}" ]; then
    echo "";
    else
    argarray[$index]=${!at}
    # echo "Is not a path. Left alone as ${argarray[$index]}"
    fi;
    done;
    echo ${argarray[*]}
    command=`echo "${argarray[*]}"`
    echo $command;
    $command

  10. Sorry, I have a quoting problem in the above script. This one fixes it:

    #!/bin/bash
    # Execute a Windows program from Cygwin by appropriately tailoring the paths in the arguments
    convert=”cygpath -aw”

    argarray[0]=”$1″;

    for ((at=2; at <= $#; at++)); do
    index=$(($at-1))
    # echo -n "Index: $index; "
    # echo "Arg:" ${!at}"; "
    for path in `ls /`; do
    # echo "Path = /$path"
    if [[ ${!at} == /$path* ]]; then
    #This is most likely a cygwin path, convert it.
    argarray[$index]="`$convert \"${!at}\"`"
    # echo "Is a path. converted to ${argarray[$index]}"
    fi;
    done;
    if [ -n "${argarray[$index]}" ]; then
    echo "";
    else
    argarray[$index]=${!at}
    # echo "Is not a path. Left alone as ${argarray[$index]}"
    fi;
    done;
    echo ${argarray[*]}
    command=`echo "${argarray[*]}"`
    $command

  11. The Jonathon/yanos bash function p4() works PERFECTLY…thank you thank you thank you, I couldn’t stand one more second using cmd.exe even just for invoking p4.exe

Leave a Reply

Your email address will not be published.