44

The find command does completely different in Windows and Unix. On Windows it is a fgrep-like utility listing matching lines in a file; on Unix -- and on Cygwin -- it list filenames matching some criteria.

Cygwin bash prepends its standard directories to the current path, so inside bash $PATH is typically /bin:/usr/bin:/cygdrive/c/WINDOWS/system32:/cygdrive/c/WINDOWS.

Begin Update to provide additional details

For example I have many scripts that use the gnu find command -- for example scripts to purge directory trees that contain no files:

purge-empty-dirs.sh
find . -depth -type d -empty | xargs rmdir -p

I also have a bat file to start my build, which uses the windows find command, which searches for lines matching a string (similar to gnu grep).

build.bat
...
dir | find "target"
if errorlevel = 1 goto no_target_dir
...

Now, for my bash script to work I need /bin to be in path before c:\windows\system32. But for my bat file to run I need c:\windows\system32 to be in path before /bin

In general we might be able to claim that all bat files should be executed with the original environment inherited by bash, not the modified one. Does that make sense?

End Update

This how it should be, but breaks the bat files executed from bash. What is the best way to address this?

Is there a way to force Cygwin to execute bat files (or even all Windows executables) with the environment it started with? I am thinking of start /i behavior of cmd.exe. I am thinking of writing my own cygstart like utility that does this, by saving the environment (or at least $PATH) in .bash_profile/.bashrc. Does that make sense?

Any other suggestions?

Edit: See also Start new cmd.exe and NOT inherit environment

Community
  • 1
  • 1
Miserable Variable
  • 28,432
  • 15
  • 72
  • 133

5 Answers5

48

If you chmod +x your.bat it works.

./your.bat

is run via cmd /c

Already answered in Why is it that Cygwin can run .bat scripts?

Community
  • 1
  • 1
rurban
  • 4,025
  • 24
  • 27
  • 2
    I suspect you don't understand the point of my question, which is that I need to execute the bat file in the original environment, which has since been changed – Miserable Variable Jul 13 '13 at 23:53
  • 1
    Yes, you are right. Generally this cannot work since `/bin` needs to override `/cygdrive/c/Windows/Systems32`. You can only write a bat launcher which strips the cygwin paths before executing `cmd /c bat`. But then you loose. It would be much better to rewrite your bat files with a shell script. bat files are horrible to read and maintain. – rurban Mar 30 '14 at 15:50
  • 1
    In a perfect world I would be able to rewrite bat files to shell scripts. But I don't live in a perfect world. See my comment [above](http://stackoverflow.com/questions/17582778/how-to-execute-a-bat-file-from-cygwin-bash-that-uses-the-windows-find-command/17635020?noredirect=1#comment25661394_17583650) – Miserable Variable Apr 01 '14 at 23:35
  • can the above method pipe the `.bat` output to a text file from bash? – jiggunjer Dec 08 '15 at 05:38
  • Guess most of us only needed to write `./x.bat` :) – Taha Paksu Nov 26 '20 at 09:00
7

I've tested a solution from here and it works nicely:

start "clean shell" /i "%windir%\explorer.exe" "\path\to\your\script.bat"

Example

to-run.bat script:

echo %PATH%
echo "TODO: some commands"
cmd

cygwin bash script, run-me.sh:

#!/bin/bash -e
set -x

SCRIPT_WINPATH=`cygpath --windows --absolute "$1"`
EXPLORER_CYGPATH=`which explorer`
EXPLORER_WINPATH=`cygpath --windows --absolute "${EXPLORER_CYGPATH}"`

cmd /C start "clean shell" /I "${EXPLORER_WINPATH}" "${SCRIPT_WINPATH}"

test:

chmod +x to-run.bat
chmod +x run-me.sh
./run-me.sh to-run.bat
Community
  • 1
  • 1
3

You can use a wrapper, say, launcher.bat, whose contents is

@echo off
setlocal
rem modify here based on your needs
set PATH=%SystemRoot%\system32;%SystemRoot%;%SystemRoot%\System32\Wbem
call %*
endlocal
exit %errorlevel%

Say you want to call cmdFUBAR.bat with arg wellDoneMS from a cygwin bash script, instead of just cmdFUBAR.bat wellDoneMS, you do cygstart -w launcher.bat cmdFUBAR.bar wellDoneMS. Of course you have to put launcher.bat into your path, or call it with full path.

Not an ID
  • 2,579
  • 2
  • 21
  • 28
2

=== In the build.bat script...

SET "DOS_FIND_EXE=%SYSTEMROOT%\System32\find.exe"
...
dir | "%DOS_FIND_EXE%" "target"
if errorlevel 1 goto no_target_dir
...
lit
  • 14,456
  • 10
  • 65
  • 119
2

The answer given by @ruslo is very useful and works just fine, but there a redundancy in it: the start "clean shell" /I does nothing here :-) It is the explorer piece that gets rid of the current cygwin env, not start /i! Try omitting it from the last line of the script, like so:

cmd /C "${EXPLORER_WINPATH}" "${SCRIPT_WINPATH}"

Same result - "pristine path"!

Perusing the help for start, it says: The new environment will be the original environment passed to the cmd.exe and not the current environment. Well, but the environment passed to cmd in this case is that of cygwin, so start /i will do nothing useful here, as one can see by typing:

cmd /c start /i cmd /c "path && pause"

The path is still that of cygwin, not the windows system!

dobriai
  • 61
  • 2