V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
varius
V2EX  ›  程序员

Linux 中为什么有些程序正常运行可以在标准输出中打印,用了重定向>或者管道|后,重定向文件及管道中无任何输入?

  •  
  •   varius · 2022-12-02 23:10:36 +08:00 · 2464 次点击
    这是一个创建于 720 天前的主题,其中的信息可能已经有所发展或是发生改变。
    如题。
    有些程序直接运行 COMMAND ,就能在屏幕中打 log 。
    但是如果在后面加上> 或者 | xargs 后,文件或管道中不能收到任何数据。
    想请教一下各位 Bash 玩的比较六的大佬们,到底什么问题?
    22 条回复    2022-12-04 17:41:57 +08:00
    moen
        1
    moen  
       2022-12-02 23:17:20 +08:00
    可能你看到其实是输出到 stderr ,直接重定向当然是没有内容
    varius
        2
    varius  
    OP
       2022-12-02 23:18:01 +08:00
    @moen 这个问题我有考虑过,然后将 stderr 重定向到 stdout 中,但是也失效。很奇怪
    gam2046
        3
    gam2046  
       2022-12-02 23:23:56 +08:00
    有些程序指的是哪些,给几个例子看,让人上来就猜是不是有点困难。
    varius
        4
    varius  
    OP
       2022-12-02 23:28:29 +08:00
    @gam2046 比如 bazel
    conanforever22
        5
    conanforever22  
       2022-12-02 23:53:11 +08:00
    我之前遇到过这样的问题,不知道和你的情况是否类似
    ```sh
    cmd_write_to_stderr 2>&1 > foo.txt # > 在 2>&1 后边的话是重定向不成功的
    ```
    但是
    ```sh
    cmd_write_to_stderr > foo.txt 2>&1 # > 在 2>&1 前边的话是没问题的
    ```
    kirory
        6
    kirory  
       2022-12-02 23:55:48 +08:00
    因为没有用 stdout / stderr, 比如 sudo 的输入用的都不是这些,而是直接读写终端
    kirory
        7
    kirory  
       2022-12-02 23:58:55 +08:00   ❤️ 2
    比如这些命令,对应的设备可能不是 1 ,可以多试几个数字
    echo Hello > /dev/pts/1
    cat < /dev/pts/1
    kirory
        8
    kirory  
       2022-12-03 00:04:54 +08:00
    @kirory 改进一下,把重定向位置改成 $(tty)
    geelaw
        9
    geelaw  
       2022-12-03 00:08:17 +08:00 via iPhone   ❤️ 1
    因为程序可以选择查看自己的标准流是哪里并选择不同的行为。比如 git diff 在 stdout 接入 terminal 的时候默认使用转义序列显示彩色,但 stdout 接入文件时默认不用。
    varius
        10
    varius  
    OP
       2022-12-03 01:01:07 +08:00
    @conanforever22 有些类似
    varius
        11
    varius  
    OP
       2022-12-03 01:01:25 +08:00
    @kirory 谢谢老哥指教,我测试一下
    varius
        12
    varius  
    OP
       2022-12-03 01:01:54 +08:00
    @geelaw 的确是的。而且现在有些 log 框架也会有类似的情况
    varius
        13
    varius  
    OP
       2022-12-03 01:02:54 +08:00
    @kirory 再请教下老哥,如果是直接读写终端的话,按道理不会出现用了管道或者重定向之后屏幕不输出的情况吧。
    luvjoey1996
        14
    luvjoey1996  
       2022-12-03 01:09:40 +08:00 via Android
    @conanforever22 参考一下 shellcheck
    bigdoing
        15
    bigdoing  
       2022-12-03 01:11:36 +08:00 via iPhone
    还是让高手来回答你们
    程序判断输出是 tty 的时候,按照行缓冲输出,有了新一行,就写
    如果是 pipe 的话,就会攒着,到一大块的时候,再写
    这种一般有参数控制,比如 grep ,就有一个参数控制
    varius
        16
    varius  
    OP
       2022-12-03 01:20:42 +08:00
    @bigdoing 请教一下,在这种情况如何可以强迫前面的有一行输出一行呢?
    jasonyang9
        17
    jasonyang9  
       2022-12-03 07:54:48 +08:00
    aloxaf
        18
    aloxaf  
       2022-12-03 08:39:06 +08:00
    @varius
    在伪终端里运行它们即可,zsh 用户的而话可以直接用 zpty 命令:
    https://github.com/lilydjwg/dotzsh/blob/master/zshrc#LL561-L561C7
    7RTDKSAK
        19
    7RTDKSAK  
       2022-12-03 15:31:00 +08:00   ❤️ 1
    @conanforever22

    因为重定向是有序地(至少在 BASH 中是有序地,其它 SHELL 我不了解)

    第一种写法:
    第一阶段:文件描述符 1 和 2 都指向屏幕(姑且说成"屏幕",方便理解),你把串流 2 重定向到了串流 1,而串流 1 又指向了屏幕,所以最终效果就是串流 2 指向了屏幕(虽然它原来也指向屏幕),串流 1 没有变化依旧指向屏幕
    第二阶段:在第一阶段(或者说在以前所有重定向阶段)基础上,串流 1 重定向到了文件(所以在屏幕上看不到了),串流 2 没有变化依旧指向屏幕
    所以最终效果就是你所说得"重定向不成功"

    第二种写法:
    略,言之有理即可(滑稽)

    另外,推荐&>file 这种写法,一次性把文件描述符 1 和 2 同时重定向到文件
    JohnBull
        20
    JohnBull  
       2022-12-03 17:32:42 +08:00
    不可能的

    肯定是太着急了,数据还在 buffer 里没刷出来呢,你就去看输出文件,发现是空的,就 sigint 了……
    varius
        21
    varius  
    OP
       2022-12-04 17:41:28 +08:00
    @jasonyang9 谢谢老哥指教
    varius
        22
    varius  
    OP
       2022-12-04 17:41:57 +08:00
    @aloxaf 谢谢老哥的提示,这是一个新思路,我去查一下 bash 里面有没有类似的实现
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1031 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 22:26 · PVG 06:26 · LAX 14:26 · JFK 17:26
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.