创建批处理文件以启动Cygwin并执行特定命令

19
我想创建一个批处理文件,启动Cygwin并执行特定的命令(该命令是读取Bash文件并在其中执行某些命令)。这是我开发的批处理文件,它在某种程度上有效。Cygwin终端会打开并尝试读取Bash文件,但无法执行其中的命令:
@ECHO OFF

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

PAUSE

我该怎么让这个起作用?


你从cygwin得到的具体错误信息是什么? - XouDo
2个回答

21

从你的批处理文件中,启动Cygwin的bash shell,并使用登录标志。 这为通过你的.bash_profile.bashrc文件设置路径和环境变量提供了基础。我相信这可能是你遇到困难的原因。

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

如果您提供有关您的bash文件性质的更多详细信息,我可以提供更具体的帮助。祝您好运。


2
非常感谢您提供关于“--login”标志的提示,这对我非常有帮助。 - manifertal

14

Patrick Kelly的有用答案指出,在Cygwin中不以login身份运行bash可能是问题的根源。

确实如此:始终将Cygwin bash作为login shell运行,因为否则关键的初始化将无法进行;特别是,$PATH变量将不包含/usr/local/bin:/usr/bin,而语言环境设置也将不正确。

为了使bash启动为login shell,则必须向bash可执行文件传递-l选项(或其长选项别名--login)。

  • 要执行您的脚本:

    • 在当前的控制台窗口中,请参见Patrick的答案

      • 请注意,除非目标脚本依赖于特定的工作目录,否则不需要使用-c和分开的cd和执行命令;像下面这样的东西就可以:

        C:\cygwin64\bin\bash -l c:\path\to\your\script
        
    • mintty.exe 中,这是 Cygwin 自带的终端应用程序(正如您所尝试的那样):

    • C:\cygwin64\bin\mintty /bin/bash -l c:\path\to\your\script
      
      请注意,从命令提示符或批处理文件执行mintty始终会打开一个新的控制台窗口,并且是异步执行的。
      另外,需要注意的是,可以使用Windows样式的路径来指定目标脚本(这意味着您也可以使用c:\cygwin64\bin\bash代替/bin/bash)。
      更重要的是,需要在两种情况下明确引用bash可执行文件,这与您尝试的方式形成对比:
      通过mintty.exe传递的选项是特定于它本身的,不会传递给bash。具体来说,您正在使用的mintty.exe选项如下(通过运行mintty --help查看所有选项):
      -l,--log FILE|-...将输出记录到文件或stdout -i,--icon FILE[,IX]...从文件加载窗口图标,IX为可选索引
      因此,-li在当前目录中创建名为i的日志文件,因为i被解释为l的选项参数,而不是单独的选项i
      然而,指定的脚本(/cygdrive/c/...)仍会被执行,但关键是不在登录shell中。
      正如上面演示的那样,您想要执行的操作需要显式调用bash可执行文件,以便选项由Bash解释。
      C:\cygwin64\bin\mintty /bin/bash -li c:\path\to\your\script
      
      此外,需要注意的是,从批处理文件中执行mintty.exe总会创建一个新的控制台窗口,并且此过程是异步的——也就是说,无论mintty.exe进程是否已终止,您的批处理文件都会立即继续执行PAUSE命令。显然,在那个新窗口中输出的任何内容都不会在原始窗口中显示。

      可选阅读:与mintty.exe窗口交互:

      注意:即使使用通常的start /wait方法从批处理文件中运行mintty.exemintty.exe仍然会异步运行。也就是说,以下尝试阻止批处理文件/命令提示符直到mintty.exe终止的方法不起作用

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

      当传递一个脚本/命令时,由 mintty.exe 创建的 Bash 会话无论如何都会在脚本终止时退出,因为即使传递了-i以指示交互式会话,bash 在这种情况下也会自动退出。

      如果你只需要在脚本终止后 检查 输出结果,则运行:

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

      请注意,一旦脚本退出,该窗口中将不再运行任何shell,因此您只能检视脚本的输出 - 没有其他操作。

      要保持一个shell开启,您需要一个变通方法

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

      请注意,此操作会在脚本退出后创建一个新的 shell 实例。


mintty 是为 Windows 子系统(GCC -mwindows)构建的,因此该应用程序不会附加到现有控制台,这就是为什么它表现为“异步”的原因。bash 是为 console 子系统(GCC -mconsole)构建的,因此会附加到当前控制台并阻止您的命令提示符。 - gavenkoa
1
@gavenkoa,从调用shell的角度来看,执行是异步的:它启动了进程,并立即返回控制权。因此,在我看来,“异步”这个术语似乎很合适。你会怎么称呼它?我知道mintty.exe是一个GUI子系统应用程序,但仅凭这一点并不能解释其行为,因为对于这样的应用程序,start /wait也可以正常工作(尝试start /wait Notepad.exe);我怀疑mintty.exe通过另一个进程“间接”启动其GUI。 - mklement0
1
我使用procmon检查了mintty的行为:初始的mintty创建了第二个mintty并立即退出。这解释了start /wait的作用:所以我错误地假设阻塞是在终端锁上。显然,/wait等待子PID,因此mintty实现了一个技巧来隐藏自己的PID。感谢您的解释:我不知道start /wait Notepad - gavenkoa
很高兴听到这个消息,@gavenkoa - 感谢您深入挖掘。 - mklement0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接