18

On Windows 10, can git-bash and cygwin shell do the same things?

What can one do but the other can't?

For example,

  1. As shells, can they both work the same as bash?
  2. What programs and commands can run in one but not in the other?

    For example, in git-bash, I can't run some Windows command:

    $  reg add "HKCU\Software\Microsoft\VisualStudio\14.0_Config\MSBuild" /v EnableOutOfProcBuild /t REG_DWORD /d 0 /f
    ERROR: Invalid syntax.
    Type "REG ADD /?" for usage.
    

    But in Cygwin, it runs well

    $  reg add "HKCU\Software\Microsoft\VisualStudio\14.0_Config\MSBuild" /v EnableOutOfProcBuild /t REG_DWORD /d 0 /f
    The operation completed successfully.
    

    originally I thought that git-bash and cygwin can both run programs in Windows. So Why doesn't git-bash work, while cygwin can?

Thanks.

11

The difference is that Cygwin knows how to process so-called "Win32" pathnames. Loosely speaking, it knows that "\" is a pathname separator and not a shell escape character like it is in Bash. The error you showed is Bash interpreting "\" as an escape character. (Edit: you might try replacing one \ with two, thus escaping the backslash, so that Bash passes the command through to reg.exe correctly.)

Having said that, while Cygwin groks Windows pathnames, it doesn't like to do so. The documentation warns you off from using them. Of course, a little back-sliding now and then doesn't hurt. But while you can run Windows programs in Cygwin, hygiene suggests you should run Windows programs in the CMD.EXE processor and UNIX ones in Cygwin for your long-term sanity.

3
  • 2
    You can use cygpath to convert between windows and unix path formats.
    – DavidPostill
    Mar 24 '17 at 14:40
  • Thanks. The pathname in my commands are used as keys in the registry table, so can "\" in them be replaced with "/"?
    – Tim
    Mar 24 '17 at 19:05
  • Maybe, but see the suggestion in the (newly edited) answer. Mar 25 '17 at 17:03
3

There is a lot of overlap between the two. But ultimately they are different implementations of bash/shall in Windows.

Cygwin has a large body of optional software you can install, including multiple different programming languages, compilers, various network tools, and so on. You can also install X and many X applications.

With git bash, you get what you get, and it's a bit more difficult to install additional tools. I actually have both on my workstation, because there's things I can't do in git bash. I've had very mixed success calling cygwin apps from the git bash window, too.

Also, cygwin is a full posix environment, not just a bash interpreter, so you can often compile non-distributed code within it, so for example if you found the source of a nice Linux tool you found, you can usually compile that tool for Cygwin. Not so much for git bash. And as I alluded above, even if you do compile it for Cygwin it likely won't work in git bash.

Other than that they are mostly very similar. It's kind of funny to see that git bash includes the cygpath command for converting Windows and Posix file paths, because git bash afaik is based on MinGW, which is a distinct solution from Cygwin.

0

I just found a difference: I can run this script in Git bash but not in Cygwin.

for file in *.xml; do
    echo "Processing file: $file"
    sed -r 's:<Autorizado>([0-9]+)</Autorizado>:<Autorizado>00013069</Autorizado>:' -i "$file"
    # ...
done

In Git bash, it process my xml files, but in Cygwin, it gives me error:

Processing file: *.xml
sed: cannot read *.xml: No such file or directory

bash --version in Git bash:

GNU bash, version 4.3.42(5)-release (x86_64-pc-msys)

in Cygwin:

GNU bash, versión 4.3.46(7)-release (x86_64-unknown-cygwin)
3
  • 1
    This just suggests that there is no file ending in .xml in the current directory the case of the cygwin test. You should show the result of ls in the current directory with the command. Jan 25 '19 at 14:35
  • I believe this is not the case since I am running the same script in two terminals at the same time. The file is there.
    – WesternGun
    Jan 29 '19 at 9:21
  • 3
    There are two possibilities: (1) There is no such file, perhaps because the cygwin script runs in a different directory. In that case the shell leaves the pattern alone (instead of replacing it with the empty string). (That sounds like an almost-always mistake until one realizes that one can pass patterns to find that way unquoted.) (2) The files' names are actually *.XML (in capitals) and the shell option nocaseglob is set in the git shell making globs case insensitive (which makes a certain sense on Windows). Jan 29 '19 at 15:46
0

Although the answer to use the cygwin git is viable, there are issue that the "git bash" version has improved, especially integration with the windows open-ssh implementation. I could be wrong about that and just haven't studied the cygwin implementation enough to fix it. YMMV. We still have the general class of problem for calling a windows executable from cygwin.

Three issues in this context (windows native gvim and git bash being my main concerns).

  1. the path to file name arguments passed to the external (windows) command.

  2. The environment the command finds itself in when it looks for configuration files (.vimrc/_vimrc/.gitconfig etc...). Since the Windows commands we are most interested in are Unix style, they mostly revolve around the $HOME variable for finding those config files. In cygwin shell that is going to be "/home/yournameisSue". But these programs are looking for the one you have in "C:/users/yourname_001" or some such.

  3. PATH. This one is trickier. I'm going with the assumption that the Windows program will not be able to launch cygwin programs and so needs the original windows path, not the cygwin one. We have that available in $ORIGINAL_PATH. That sucks in that you can't easily do

    :! somecygwincommand

from gvim, but that didn't seem to work anyway and I'm not solving that today.

My solution:

First set a variable with the full path windows style HOME. You can use forward slash just fine to simplify things, so the command "cygpath -m" can do that. I found a variable in my cygwin environment that has the proper directory name -- USERPROFILE. It has "C:\Users\myname_001" value. I set a new variable to hold this in .bashrc:

WINHOME=$(cygpath -m "$USERPROFILE")
$ echo $WINHOME
C:/Users/myname_000

Now I can start the non-cygwin git (like from git bash) or natively installed gvim like this (assuming they are in PATH. If not use a full path name version that cygwin understands!):

HOME=$WINHOME gvim $@ 2>&1 &

That at least makes it read my _vimrc file in my Windows home directory. Progress. But the command line argument processing is an issue when file paths are involved. Sure a relative path name like a file in the current directory works fine. When windows version of gvim starts up it asks the OS what directory it is in and doesn't know anything about the cygwin munging of it to /cygwin/c or whatever. But if you have a full path it gets messy.

I created a function to munge the argument list for paths. It creates a new array named _pathargs that we will use in place of $@.

pathargs() {
    _pathargs=() # initialize empty array
    for a in $@
    do
        if [[ "$a" =~ ^- || ! ( -f "$a" || -d "$a" ) ]]; then 
            # starts with a dash or is not a file or directory
            _pathargs+=("$a")
        else # is a file or directory so give a full windows path name
            b=$(cygpath -m -a $a)
            _pathargs+=("$b")
        fi
    done
}

Now my function to start gvim (which I named "v") and one to run a git bash git command are as follows. Note the setting of HOME and PATH before calling the windows executable. This syntax "exports" those environmental variables for the command that is executed without touching the ones running in your shell:

export WINHOME=$(cygpath -m "$USERPROFILE")
alias cdwh='cd $WINHOME' # convenience alias
v() {
    pathargs $@
    # set HOME var to one gvim understands for finding config files like .vimrc _vimrc
    HOME="$WINHOME" PATH="$ORIGINAL_PATH" gvim ${_pathargs[*]}  2>&1 &
}
git() {
    pathargs $@
    # function to have same name as executable, so use "command" to protect 
    # against recursive call of the function itself
    HOME="$WINHOME" PATH="$ORIGINAL_PATH" command git ${_pathargs[*]}
}

It all seems to work; however, if you have installed "git" with cygwin setup it will be in your path before the git bash (windows) version. In that scenario you will need to give the full path of the git executable in the function definition in lieu of using "command git". Remember to use a variant of it that cygwin understands.

HTH

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.