Creating batch file to start cygwin and execute specific command
Asked Answered
H

2

19

I want to create a batch file thats start cygwin and executes a specific command (The command is to read a bash file and executes some command inside it).

This is the batch file that I have developed, it works to some extent. the cygwin terminal opens and tries to read the bash file, but cannot execute the commands inside:

@ECHO OFF

C:\cygwin64\bin\mintty.exe -li /cygdrive/c/(path-to-bash-file-location)/(MyBashFile)

PAUSE

How can I make this work?

Handgun answered 7/4, 2017 at 5:8 Comment(1)
What is the specific error message you're getting from cygwin?Estragon
R
21

From your batch file, launch Cygwin's bash shell and use the login flag. This provides a foundation for setting path and environment variables through your .bash_profile or .bashrc files. I believe this may be the source of your difficulties.

@ echo off
C:\cygwin64\bin\bash --login -c "cd ~/path/to/desired; ./mybashfile.sh"

If you provide more details about the nature of your bash file, I can be more specific. Good luck.

Ricardo answered 8/4, 2017 at 20:28 Comment(1)
Thank you very much the hint about "--login" flag was very helpful.Handgun
B
14

Patrick Kelly's helpful answer points out that not running bash as a login shell in Cygwin may be the source of the problem.

Indeed: Always run Cygwin bash as a login shell, because crucial initializations will otherwise not take place; notably, the $PATH variable won't contain /usr/local/bin:/usr/bin, and the locale won't be set correctly.

In order to make bash start a login shell, the bash executable must be passed the -l option (or its longer alias, --login).

  • To execute your script:

    • in the current console window, see Patrick's answer.

      • Note that unless the target script relies on a particular working directory, use of -c with separate cd and execution commands is not strictly necessary; something like the following will do:

        C:\cygwin64\bin\bash -l c:\path\to\your\script
        
    • in mintty.exe, the terminal application that Cygwin comes with (as you've tried):

      C:\cygwin64\bin\mintty /bin/bash -l c:\path\to\your\script
      
      • Note that executing mintty from a Command Prompt or batch file invariably opens a new console window, and does so asynchronously.

Note how a Windows-style path can (alternatively) be used to specify the target script (which means you could have used c:\cygwin64\bin\bash instead of /bin/bash too).

More importantly, note how an explicit reference to the bash executable is required in both cases, which contrasts with what you tried:


Options you pass to mintty.exe are specific to it - they're not passed through to bash. Specifically, mintty.exe options you're using are (see all of them by running mintty --help):

  • -l, --log FILE|- ... Log output to file or stdout
  • -i, --icon FILE[,IX] ... Load window icon from file, optionally with index

Therefore, -li creates a log file named i in the current directory, because i is interpreted as the l's option-argument, not as separate option i.

The specified script (/cygdrive/c/...) still executes, however - but, crucially, not in a login shell.

What you meant to do requires an explicit call to the bash executable, as demonstrated above, so that the options are interpreted by Bash:

C:\cygwin64\bin\mintty /bin/bash -li c:\path\to\your\script

Also, as noted, executing mintty.exe from a batch file invariably creates a new console window, and does so asynchronously - that is, your batch file immediately proceeds to the PAUSE command, irrespective of whether the mintty.exe process has terminated yet or not.

Obviously, whatever is output in that new window will not be visible in the original window.


Optional reading: interacting with a mintty.exe window:

Caveat: mintty.exe runs asynchronously even when using the usual start /wait approach from a batch file; that is, the following attempt to block a batch file / command prompt until mintty.exe terminates does not work:

start /wait "" "c:\cygwin64\bin\mintty" # !! DOES NOT WORK - still asynchronous

When passed a script / command, the Bash session created by mintty.exe will invariably exit when the script terminates, because bash - even when it's passed -i to indicate an interactive session - will automatically exit in that case.

If all you need is to inspect the output after the script terminates, run:

c:\cygwin64\bin\mintty -h always /bin/bash -l /cygdrive/c/path/to/bash-script

Note that no shell is running in that window once the script exits, so all you can do is inspect the script's output - nothing more.

To keep a shell open, you need a workaround:

c:\cygwin64\bin\mintty /bin/bash -lc "/cygdrive/c/path/to/bash-script; exec /bin/bash"

Note that this creates a new shell instance after the script exits.

Bondmaid answered 8/4, 2017 at 21:58 Comment(4)
mintty is built for windows subsystem (GCC -mwindows) so the app doesn't attach to the existing console, that's why it acts "asynchronously". bash is built for console subsystem (GCC -mconsole) so attaches to the current console and blocks your command prompt.Text
@gavenkoa, the execution is asynchronous from the perspective of the calling shell: it launches the process, and control returns to it right away. Therefore, the term "asynchronous" seems appropriate to me. What would you call it? Understood that that mintty.exe is a GUI-subsystem application, but that alone doesn't explain the behavior, given that start /wait works fine for such applications (try start /wait Notepad.exe); I suspect that mintty.exe launches its GUI indirectly, via another process.Bondmaid
I checked mintty behavior with procmon: initial mintty creates second mintty and immediately exits. This explains start /wait: so I made wrong assumption that blocking is on terminal lock. Apparently /wait waits for child PID, so mintty implemented a trick to hide own PID. Tnx for explanation: I didn't know about start /wait Notepad!Text
Glad to hear it, @Text - thanks for digging deeper.Bondmaid

© 2022 - 2024 — McMap. All rights reserved.