【问题标题】:Redirect batch stderr to file将批处理标准错误重定向到文件
【发布时间】:2010-10-29 10:49:25
【问题描述】:

我有一个执行 java 应用程序的批处理文件。我正在尝试对其进行修改,以便在发生异常时将 STDERR 写入文件。

看起来像这样:

start java something.jar method %1 %2 2>> log.txt

有没有办法也可以将参数 %1 和 %2 写入 log.txt 文件?我不想每次调用此批处理文件时都将其写入日志文件,仅在发生异常时才写入。

我尝试寻找一种将 STDERR 重定向到变量的方法,但我无法弄清楚。理想情况下,我希望日志文件看起来像:

Batch file called with parameters:
- "first arg"
- "second arg"
Exception: 
java.io.exception etc...

------------------------------------

Batch file called with parameters:
- "first arg"
- "second arg"
Exception: 
java.io.exception etc...

【问题讨论】:

    标签: windows batch-file cmd stderr


    【解决方案1】:

    这样的东西怎么样(未经测试):

    @echo off
    @echo Batch file called with parameters: >> log.txt
    @echo - %1 >> log.txt
    @echo - %2 >> log.txt
    start java something.jar method %1 %2 2>> log.txt
    

    【讨论】:

    • 但这会在每次调用批处理文件时记录输出,不是吗?如果可能的话,我想避免这种情况,如果 java 应用程序抛出异常,就让它记录下来。
    【解决方案2】:

    我没有完全理解您的要求,但这里有一些信息可能会有所帮助...

    您可以在 .cmd 或 .bat 文件中将 stderr 与 stdout 分开重定向。要重定向 stderr,请使用以下内容:

    MyCommand.exe > command.stdout.txt  2> command.stderr.txt
    

    然后,您可以检查 command.stderr.txt 的内容,如果有,请将其与 command.stdout.txt 连接到您的日志文件中。或者你可以在任何情况下连接它。如果您愿意,还可以将您运行的命令回显到最终日志文件中。

    您还可以使用 %ERRORLEVEL% 环境变量检查批处理文件中的退出代码。 Exe 文件应在出现错误时设置 ERRORLEVEL。我不知道 java.exe 是否这样做。如果它是 Windows 上的好公民,它应该。这可能是确定 Java 应用程序是否以错误条件退出的另一种方法。但这并不能保证 stderr 一无所获。例如,Java 应用程序可能会打印出异常和堆栈跟踪,然后以代码 0 退出,这表示成功。在这种情况下,stderr 会在其中包含垃圾,但 ERRORLEVEL 会为零。

    编辑:s/ERROR_LEVEL/ERRORLEVEL

    【讨论】:

    • 我试图避免每次调用此批处理文件时写入文件。这个批处理文件经常被调用,它存在于一个已经 IO 饱和的服务器上。
    • 有点误读您的答案。我已经将标准错误写入日志文件,但我也想尝试写出传递给批处理文件的参数。我只想在将 stderr 写入日志时记录这些参数。
    • 它被称为 %ERRORLEVEL%,而不是 %ERROR_LEVEL%。此外,您应该使用“if errorlevel 1 ...”来检查它,而不是与实际上不存在的 %errorlevel% 进行比较。
    【解决方案3】:

    尝试使用ERRORLEVEL

    java something.jar method %1 %2 2>> log.txt
    IF %ERRORLEVEL% NEQ 0 GOTO Error
    
    Error:
    @ECHO There was an error
    @ECHO Arg 1: %1 >> log.txt
    @ECHO Arg 2: %2 >> log.txt
    

    【讨论】:

    • 我刚试过这个,errorlevel总是零,即使java抛出异常。
    • 如果java主类是你写的,你可以把整个东西包装在一个try/catch中,并在catch块中使用exit(1)来设置环境中的错误级别
    【解决方案4】:

    我看到的唯一可行的解​​决方案是将 stderr 重定向到一个临时文件

    java blah.jar %1 %2 2>stderr
    

    然后查看是否已将某些内容写入文件并在这种情况下写入日志。

    for %%i in (stderr) do if %%~zi GTR 0 (
        echo Parameters: %1 %2 >>log.txt
        type stderr >> log.txt
    )
    

    如果批次不是按顺序运行而是同时运行,您需要找到一些东西来唯一化临时变量:

    set file=%time::=%
    set /a file=file
    set file=%file%%random%
    java blah.jar %1 %2 2>stderr_%file%
    for %%i in (stderr) do if %%~zi GTR 0 (
        echo Parameters: %1 %2 >>log.txt
        type stderr >> log.txt
    )
    

    这将避免多个运行批次之间的冲突。但是,您目前没有使用任何东西来锁定对日志文件的写入,并且当其他内容写入其中时,事情可能会显得不合适(对于其他批次,您可能会在 echotype 命令中交错,或者,当您也将 java 的输出重定向到该文件,那么它可能会与 java 程序的常规输出混淆:

    参数:foo bar 一些常规输出 参数:foo2 bar2 更多输出 Blah 的 NullPointerException:在参数之后我们真正想要的 Blah 处的 IOException:此异常属于参数 foo2 bar2

    您可以使用另一个文件作为信号量来写入日志以避免批处理输出混合:当您想要写入日志时创建文件 [copy nul file],然后在尝试创建它之前将其删除检查它是否真的存在并等到它消失。但是,您不能对混合到文件中的标准输出日志做任何事情,除非您也对标准输出使用该临时文件方法(并且当 Java 程序完成时,只需将标准输出日志 typelog.txt,但是,再次使用信号量。

    【讨论】:

      【解决方案5】:

      这样的批处理文件应该可以解决问题。

      start_prog.cmd

      CALL :Start_Prog arg1 arg2
      GOTO :EOF
      
      :Start_Prog
          something.py %1 %2 2>&1 1>nul | "C:\Python26\python.exe" format_output.py %1 %2 >>log.txt
          GOTO :EOF
      

      在这里,我通过管道传递 stderr 并将参数作为参数传递。然后将输出附加到 log.txt 文件中。

      扔掉标准输出

      1>nul
      

      将标准错误重定向到标准输出

      2>&1
      

      将标准错误导入脚本以格式化输出,并将参数作为参数传递。

      | "C:\Python26\python.exe" format_output.py %1 %2
      

      将输出附加到 “log.txt”

      >>log.txt
      

      在我的系统上我需要调用 python.exe 否则管道不起作用。

      这是我使用的两个文件“something.py”“format_output.py”

      something.py

      import sys
      print >>sys.stdout, " ".join(sys.argv[1:])
      print >>sys.stderr, "java.io.exception etc..."
      

      format_output.py

      import sys
      
      print "Batch file called with parameters:"
      for arg in sys.argv[1:]:
          print '- "{0}"'.format(arg)
      
      print "Exception:"
      for line in sys.stdin:
          print line
      

      最后是输出。

      log.txt

      Batch file called with parameters:
      - "arg1"
      - "arg2"
      Exception:
      java.io.exception etc...
      

      唯一缺少的是总是将某些内容写入“log.txt”文件。

      为了进一步整理,我会将日志文件写入 "format_output.py"

      然后您可以添加一个检查以查看程序中的 stderr 是否为空白。

      【讨论】:

      • 除非我真的弄错了,否则逻辑会因 2>&1 1>nul 而失败。您将所有和任何输出发送到 NUL,因此没有任何东西将管道跳到 python。很遗憾,我无法测试它,是吗?
      【解决方案6】:

      这样的事情可能会奏效:

      javastart.cmd

      @echo off
      set params=%*
      for /f "delims=" %%e in ('java something.jar method %1 %2 ^>nul') do (
          echo Batch file called with parameters:>>log.txt
          echo - Args[]: %*>>log.txt
          echo - Arg[1]: %1>>log.txt
          echo - Arg[2]: %2>>log.txt
          echo Exception: %%e
      )
      

      我自己不是 java 程序员,我无法测试这个输出/情况,但是:

      1: %* 表示每个参数,从第一个到最后一个(即使是 %12,尽管它不是直接可用的.. ),无论格式如何。使用它可能比划定它们更好。即使间距/引用错误,您也将拥有完整的参数。我在日志中添加了一行,以显示整行,然后显示参数。如果是错误的论点,您可以看到问题出在哪里。

      2: 将标准输出发送到 null (^>nul) 只会保留标准错误输出,设置为 %%e

      3: 无论是在 do 部分,只会发生 for 测试语句实际上有任何输出,即如果 %%e 已设置。

      话虽如此,您必须测试脚本并查看异常是否实际发送到 stderr,或者像其他一些软件一样,即使发生错误也发送到 stdout。

      我希望这会有所帮助。

      【讨论】:

        猜你喜欢
        • 2012-11-04
        • 1970-01-01
        • 1970-01-01
        • 2017-09-26
        • 2022-01-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多