如何确定 powershell 在终端输出的信息是 stdout 还是 stderr? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
xinghen57
V2EX    PowerShell

如何确定 powershell 在终端输出的信息是 stdout 还是 stderr?

  •  
  •   xinghen57 2023-12-12 11:36:02 +08:00 2653 次点击
    这是一个创建于 735 天前的主题,其中的信息可能已经有所发展或是发生改变。

    最近 powershell 中用 ffmpeg ,发现它终端的输出竟然走的 stdrr 。

    请问 v 友,有方法确认终端输出是 stdout 还是 stderr 吗?或确定终端输出的 stream 号?

    17 条回复    2023-12-12 23:31:26 +08:00
    matepi
        1
    matepi  
       2023-12-12 11:46:20 +08:00   1
    你是否需要
    2>&1
    把 stderr 输出重定向到 stdout ?

    如果是程序环境内调用,是否考虑加一层 shell 环境来调用? cmd /C 或者 sh -c
    xinghen57
        2
    xinghen57  
    OP
       2023-12-12 13:53:48 +08:00
    @matepi #1 谢谢,想问的不是重定向。
    我的意思是,终端上有一行输出,如果没有报错信息,通常我会当成 stdout 。但 ffmpeg ,额,这个有报错信息,ffprobe ,这个没报错信息,它的输出却走的 stderr ,也即 stream 2 。
    比如的代码

    ```
    # powershell 下
    ffprobe -i 'video.mp4'

    # 输出如下
    ffprobe version 6.0-full_build-www.gyan.dev Copyright (c) 2007-2023 the FFmpeg developers
    built with gcc 12.2.0 (Rev10, Built by MSYS2 project)
    configuration: --enable-gpl --enable-version3 --enable-static --disable-w32threads --disable-autodetect --enable-fontconfig --enable-iconv --enable-gnutls --enable-libxml2 --enable-gmp --enable-bzlib --enable-lzma --enable-libsnappy --enable-zlib --enable-librist --enable-libsrt --enable-libssh --enable-libzmq --enable-avisynth --enable-libbluray --enable-libcaca --enable-sdl2 --enable-libaribb24 --enable-libdav1d --enable-libdavs2 --enable-libuavs3d --enable-libzvbi --enable-librav1e --enable-libsvtav1 --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxavs2 --enable-libxvid --enable-libaom --enable-libjxl --enable-libopenjpeg --enable-libvpx --enable-mediafoundation --enable-libass --enable-frei0r --enable-libfreetype --enable-libfribidi --enable-liblensfun --enable-libvidstab --enable-libvmaf --enable-libzimg --enable-amf --enable-cuda-llvm --enable-cuvid --enable-ffnvcodec --enable-nvdec --enable-nvenc --enable-d3d11va --enable-dxva2 --enable-libvpl --enable-libshaderc --enable-vulkan --enable-libplacebo --enable-opencl --enable-libcdio --enable-libgme --enable-libmodplug --enable-libopenmpt --enable-libopencore-amrwb --enable-libmp3lame --enable-libshine --enable-libtheora --enable-libtwolame --enable-libvo-amrwbenc --enable-libilbc --enable-libgsm --enable-libopencore-amrnb --enable-libopus --enable-libspeex --enable-libvorbis --enable-ladspa --enable-libbs2b --enable-libflite --enable-libmysofa --enable-librubberband --enable-libsoxr --enable-chromaprint
    libavutil 58. 2.100 / 58. 2.100
    libavcodec 60. 3.100 / 60. 3.100
    libavformat 60. 3.100 / 60. 3.100
    libavdevice 60. 1.100 / 60. 1.100
    libavfilter 9. 3.100 / 9. 3.100
    libswscale 7. 1.100 / 7. 1.100
    libswresample 4. 10.100 / 4. 10.100
    libpostproc 57. 1.100 / 57. 1.100
    Input #0, matroska,webm, from '.\洞穴 burrow.mkv':
    Metadata:
    ENCODER : Lavf60.3.100
    Duration: 00:05:19.02, start: 0.000000, bitrate: 1756 kb/s
    Stream #0:0: Video: h264 (High), yuv420p(tv, bt709, progressive), 1920x1080 [SAR 1:1 DAR 16:9], 29.97 fps, 29.97 tbr, 1k tbn
    Metadata:
    HANDLER_NAME : ISO Media file produced by Google Inc.
    VENDOR_ID : [0][0][0][0]
    DURATION : 00:05:18.985000000
    Stream #0:1(eng): Audio: opus, 48000 Hz, stereo, fltp
    Metadata:
    DURATION : 00:05:19.016000000

    ```

    有什么方式能确定输出是走的 stdout 还是 stderr ,或者其他 stream 么?

    查了官方文档,没找到相关内容。
    xinghen57
        3
    xinghen57  
    OP
       2023-12-12 14:13:55 +08:00
    @matepi #1
    ```powershell
    function Write-Messages
    {

    Write-Host "Host message"
    Write-Output "Output message"
    Write-Verbose "Verbose message"
    Write-Warning "Warning message"
    Write-Error "Error message"
    Write-Debug "Debug message"
    }

    Write-Messages

    # 输出结果如下

    Host Messages
    Output Messages
    WARNING: Warning Messages
    Write-Messages: Error Messages
    ```

    上面的代码,可以看到,终端显示的输出,可能是 stdout ,也可能是 stderr ,还可能是 warning 。

    所以如果在终端看到一段输出结果,怎么确定是 stdout ,或 stderr ,还是 warning ?
    wangtian2020
        4
    wangtian2020  
       2023-12-12 14:56:49 +08:00
    const { exec } = require('child_process');

    // 要执行的 PowerShell 命令
    const powershellCommand = 'Get-Process'; // 这里用一个简单的示例命令

    // 执行 PowerShell 命令
    const child = exec(`powershell.exe -Command "${powershellCommand}"`, (error, stdout, stderr) => {
    if (error) {
    console.error(`Error: ${error.message}`);
    return;
    }
    if (stderr) {
    console.error(`stderr: ${stderr}`);
    return;
    }
    console.log(`stdout: ${stdout}`);
    });

    // 监听子进程关闭事件
    child.on('close', (code) => {
    console.log(`子进程退出,退出码 ${code}`);
    });



    用 nodejs 执行命令行,回调里面 stdout 和 stderr 是区分清楚的两个不同对象
    ns09005264
        5
    ns09005264  
       2023-12-12 14:58:40 +08:00
    通过管道符导入到其他接受 stdin 的程序里试试,比如 vim 。像这样: ffmpeg command | vim ,vim 里没有输入就不是 stdin
    huangmiaomiao233
        7
    huangmiaomiao233  
       2023-12-12 15:36:53 +08:00
    重定向不就知道了,在末尾加 1>out.log 2>err.log ,可以只写其中一个,那么就只会显示另一个
    Richex
        8
    Richex  
       2023-12-12 20:33:41 +08:00   1
    和 Linux 一样可以用 echo $?

    [Imgur]( https://imgur.com/ClJK2sn)
    xinghen57
        9
    xinghen57  
    OP
       2023-12-12 20:34:11 +08:00
    @wangtian2020 #4
    @ns09005264 #5
    @Tumblr #6
    @huangmiaomiao233 #7
    感谢诸位。最简单直接的是用重定向,就像 @huangmiaomiao233 #7 说的,也即靠经验和调试。

    其实我向寻找的是类似 Get-Member 的命令,直接可以显示输出内容去了 stream x ,貌似没有这类命令。
    xinghen57
        10
    xinghen57  
    OP
       2023-12-12 20:36:29 +08:00
    @Tumblr #6 这两篇我都看过,里面只是介绍了 stream 。
    下面我找到的这篇有兴趣兄台可以看看,说的更深一些。

    Understanding Streams, Redirection, and Write-Host in PowerShell
    https://devblogs.microsoft.com/scripting/understanding-streams-redirection-and-write-host-in-powershell/
    xinghen57
        11
    xinghen57  
    OP
       2023-12-12 20:45:11 +08:00
    @Richex #8 并不行的。

    情况一:
    ```powershell

    ffprobe -i 'video.mp4'

    echo $?
    ```
    此时 echo 输出 true ,ffprobe 输出实际走的 stderr 。

    情况二:
    ```powershell

    ffmpeg -i 'video.mp4'

    echo $?
    ```
    此时 echo 输出 false ,ffmpeg 输出实际走的 stderr 。

    上述两种情况,powershell 内核的 windows terminal 都会显示 ffmpeg 或 ffprobe 的输出。
    也即 echo $? 无法判断输出用的是 stream 几。
    Richex
        12
    Richex  
       2023-12-12 21:12:18 +08:00
    看起来 ffmpeg 就是这么设计的吧,如果需要输出到 stdout 除了重定向也可以试着找一下官方提供的相关参数,例如:

    ffprobe -i "in.mp4" -show_format > info.txt
    ffprobe -i "in.mp4" -show_format -of json > info.json

    从你的问题上来看,程序同时输出 stdout 和 stderr 是很平常的事情,所以如果你的问题是怎么确认终端输出是 stdout 还是 stderr 的话,个人感觉这个问题不太成立。

    但其实绝大部分程序都会遵守 exit code ,即 0 是正常执行完成,非 0 异常,实际测试 ffmpeg 也是这样,
    所以如果只是想知道是否执行成功其实判断 exit code 就足够了。而程序执行成功后和失败后的输出也是可预期的,判断一下 exit code 再从两个输出中根据需要读取就好了。
    xinghen57
        13
    xinghen57  
    OP
       2023-12-12 21:48:54 +08:00
    @Richex #12 感谢回答。
    通常的逻辑确是你说的这样。通常 error 信息会有 error 提示。exit code 确是可以判断正常与否。
    因此,我认为 exit code 0 的输出应该走 stdout stream 。

    ffprobe -i 'video.mp4'

    上面命令,exit code 0 ,但输出却走了 stderr 。

    而你给出的命令

    ffprobe -i "in.mp4" -show_format > info.txt

    它的输出使用的是 stdout stream ,命令的 exit code 1 。

    很令人费解。

    也是因此,才会有帖子的疑问,想找有没有显示输出 stream 编号的命令。
    Richex
        14
    Richex  
       2023-12-12 22:33:57 +08:00
    我的理解是 ffprobe -i 'video.mp4' 在终端输出的那些信息 ffmpeg 官方认为只是辅助信息或者说是调试信息,并不作为程序输出,所以 exit 0 并且 stdout 是空算是正常情况。

    或者将 ffprobe 当成一个“在终端'查看'文件信息”的工具,看起来好理解一点,在我看来这是 ffmpeg 的一种“选择”,自然也没有对错之分了。当然关于怎么输出应该交给官方了,我们在这讨论也起不到啥作用。

    在我这里 ffprobe -i "in.mp4" -show_format > info.txt 命令的 exit code 为 0 ,你是说在你那边是 1 吗?

    目前我还不是太理解你想要解决的问题,方便的话可以描述一下细节,或者“确定终端输出的 stream 号”是基于什么确定?

    比如这个问题:如果在终端看到一段输出结果,怎么确定是 stdout ,或 stderr ,还是 warning ?

    ffmpeg 已经将对应信息分别输出到 stdout, stderr 和 warning 这是已经确定的,应该怎么理解“怎么确定”?

    我感觉 OP 目的好像是想要从 stderr 中读取信息的意思?
    xinghen57
        15
    xinghen57  
    OP
       2023-12-12 23:10:43 +08:00
    @Richex #14 exit code 为 0 ,我打错了。

    > 我的理解是 ffprobe -i 'video.mp4' 在终端输出的那些信息 ffmpeg 官方认为只是辅助信息或者说是调试信息,并不作为程序输出,所以 exit 0 并且 stdout 是空算是正常情况。

    你说的这种思路,我特意用 yt-dlp 对比了一下。还真是这样。

    yt-dlp 中有一条输出:
    “WARNING: [youtube] Preferring "zh-CN" translated fields. Note that some metadata extraction may fail or be incorrect.”
    这条输出字面上应属于 warning ,但实际却被输出到 stderr ,在 powershell output stream 的编号是 2 。

    ffprobe 也是类似的“选择”,姑且认为是 ffmpeg 的选择。如果说是辅助或调试信息,放 information stream 或 debug stream 中可能更不容易让人迷惑。毕竟 powershell 提供了 6 条 stream ,其中就有 information stream (编号 6 ) 和 debug stream (编号 5 )。

    我不太确定 bash 中是否只有 stdin 、stdout 和 stderr 。如果只有这 3 个,这么设计也没问题,但如果和 powershell 一样有多个 output stream ,辅助调试信息放 stderr 就容易让不熟悉的人迷惑。

    ffprobe 的标准格式是 “ ffprobe [OPTIONS] INPUT_FILE”。
    我当时默认 “ffprobe -i 'video.mp4'” 输出应该放到 stdout ,打算从其输出提取信息却遇到无法提取情况,最后发现原因是输出被放到了 stderr 。因此,产生了是否有现成命令识别 output stream 编号的想法。
    Richex
        16
    Richex  
       2023-12-12 23:25:14 +08:00
    @xinghen57 明白了

    我猜测是 ffmpeg 没有对 PowerShell 做处理,更多的还是从 Linux 平台出发做的。

    yt-dlp 的代码里面 WARNING 也确定是直接输出到 stderr:

    https://github.com/yt-dlp/yt-dlp/blob/d5d1517e7d838500800d193ac3234b06e89654cd/yt_dlp/YoutubeDL.py#L1032

    没有考虑 PowerShell 的 warning 等通道:

    https://github.com/yt-dlp/yt-dlp/blob/d5d1517e7d838500800d193ac3234b06e89654cd/yt_dlp/YoutubeDL.py#L609-L611
    xinghen57
        17
    xinghen57  
    OP
       2023-12-12 23:31:26 +08:00
    @Richex #16 刚才的交流之后,也有类似的猜测。总是,再次感谢。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     1045 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 30ms UTC 23:07 PVG 07:07 LAX 15:07 JFK 18:07
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86