如何在Cygwin Bash中执行使用Windows查找命令的批处理文件

44

find命令在Windows和Unix上的作用完全不同。在Windows上,它是类似于fgrep的工具,用于列出文件中匹配的行;而在Unix上 - 以及在Cygwin上 - 它会列出符合某些条件的文件名。

Cygwin bash在当前路径之前添加了其标准目录,因此在bash内部,$PATH通常为/bin:/usr/bin:/cygdrive/c/WINDOWS/system32:/cygdrive/c/WINDOWS

开始更新以提供更多细节

例如,我有许多使用GNU find命令的脚本 - 例如清除不包含文件的目录树的脚本:

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

我还有一个批处理文件来启动我的构建,它使用Windows的find命令来搜索匹配某个字符串的行(类似于gnu grep)。

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

为使我的bash脚本正常运行,需要在c:\windows\system32之前将/bin添加到路径中。但是为了使我的bat文件运行,需要将c:\windows\system32添加到路径中/bin之前。

一般来说,我们可能会认为所有的bat文件都应该在继承了bash的原始环境之后执行,而不是修改后的环境。这有意义吗?

更新结束

这种方法是正确的,但会破坏从bash执行的bat文件。如何解决这个问题呢?

是否有一种方式可以强制Cygwin使用它启动时的环境执行bat文件(甚至是所有 Windows可执行文件)?我正在考虑cmd.exe的start /i行为。我正在考虑编写自己的类似于cygstart的实用程序,并将环境(或至少$PATH)保存在.bash_profile/.bashrc中。这有意义吗?

还有其他建议吗?

编辑:另请参见Start new cmd.exe and NOT inherit environment

5个回答

48

2
我怀疑您没有理解我的问题的要点,即我需要在原始环境中执行bat文件,而该环境已经发生了变化。 - Miserable Variable
1
是的,你说得对。 通常这种方法行不通,因为/bin目录必须覆盖/cygdrive/c/Windows/Systems32。 你只能编写一个批处理启动器,在执行cmd /c bat前删除Cygwin路径。但这样做你会失去很多东西。最好重写你的批处理文件为shell脚本。批处理文件难以阅读和维护。 - rurban
1
在一个完美的世界里,我可以重写bat文件为shell脚本。但是我不生活在一个完美的世界中。请参见我的评论上面 - Miserable Variable
以上的方法能否从 Bash 将 .bat 的输出导入到文本文件中? - jiggunjer
我想大多数人只需要写./x.bat :) - Taha Paksu

7

我测试了这里的解决方案,它非常有效:

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

示例

to-run.bat 脚本:

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

cygwin bash脚本,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}"

测试:

chmod +x to-run.bat
chmod +x run-me.sh
./run-me.sh to-run.bat

谢谢。另一个问题也讨论了启动不继承当前环境的进程的相同问题。 - Miserable Variable
在Cygwin上已经有了/bin/run,因此run.sh可能不是最好的名称。 - Miserable Variable
这只是为我弹出一个文件夹浏览器窗口。 - Samuel

3
您可以使用一个包装器,比如 launcher.bat,其内容为:
@echo off
setlocal
rem modify here based on your needs
set PATH=%SystemRoot%\system32;%SystemRoot%;%SystemRoot%\System32\Wbem
call %*
endlocal
exit %errorlevel%

假设你想在cygwin bash脚本中使用参数wellDoneMS调用cmdFUBAR.bat,而不是简单地运行cmdFUBAR.bat wellDoneMS,则使用命令cygstart -w launcher.bat cmdFUBAR.bar wellDoneMS。当然,你需要将launcher.bat放入你的路径中,或使用完整路径调用它。


2

=== 在 build.bat 脚本中...

SET "DOS_FIND_EXE=%SYSTEMROOT%\System32\find.exe"
...
dir | "%DOS_FIND_EXE%" "target"
if errorlevel 1 goto no_target_dir
...

这适用于 find.exe,但不适用于所有批处理文件的一般问题。 - Miserable Variable

2

@ruslo提供的答案非常有用,很好地解决了问题。但是其中存在一些冗余:在这里start "clean shell" /I没有任何作用 :-) 它是explorer这部分将当前cygwin环境清除,而不是start /i!尝试从脚本的最后一行中省略它:

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

相同的结果 - “原始路径”!

查看start的帮助文档,它说:新环境将是传递给cmd.exe的原始环境而不是当前环境。但是,在这种情况下传递给cmd的环境是cygwin的环境,因此在这里使用start /i将没有任何有用的作用,可以通过键入以下内容来查看:

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

路径仍然是 cygwin 的路径,而不是 Windows 系统的路径!

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