【问题标题】:Why does docker pseudo-tty mangle output when piped to other command?为什么当通过管道传输到其他命令时 docker 伪 tty 会破坏输出?
【发布时间】:2019-02-15 12:43:00
【问题描述】:

当 docker 输出通过管道传输到其他命令时,为什么 docker 中的伪 tty 选项会修改输出?

Docker 在使用-t 选项运行时使用CRLF 行尾。所以这是我的 2 个命令,将 CR 添加到另一个命令以使其输出相同。

❯ docker run --rm -ti bash bash -c "echo -n $'\n\n\n'" | od -c
0000000  \r  \n  \r  \n  \r  \n

❯ docker run --rm bash bash -c "echo -n $'\r\n\r\n\r\n'" | od -c
0000000  \r  \n  \r  \n  \r  \n

两个命令都通过管道传输到 while read -loop(我希望两个输出相同)

❯ while read -r out; do echo A; done < <(docker run --rm -ti bash bash -c "echo -n $'\n\n\n'")
A
 A
  A

❯ while read -r out; do echo A; done < <(docker run --rm bash bash -c "echo -n $'\r\n\r\n\r\n'")
A
A
A

为什么会这样?为什么伪 tty 会中断输出?它不应该只告诉docker输入是终端设备吗?

当然,不将-it 用于非交互式脚本是一个有效的解决方案,但不回答“为什么”。

【问题讨论】:

    标签: bash docker tty


    【解决方案1】:

    当提供--tty 选项时,docker 客户端似乎将标准输入和标准输出设置为原始模式。在cli/command/container/hijack.go 中定义的函数setupInput() 中有对setRawTerminal(streams) 的调用,它将标准输入和标准输出设置为原始模式(github link)。

    据我所知,这种原始模式会传播回您正在使用的终端。您可以通过从以下示例中删除 stty -raw 并按顺序运行它们来注意到这一点。

    简而言之,原始模式意味着终端不应该做任何线路处理,即终端不作用于 CR (\r)。

    没有 docker 客户端的简单演示:

    ❯ while read -r out; do echo A; done < <(bash -c "stty raw; echo -n $'\n\n\n'")   
    A
     A
      A
    
    ❯ while read -r out; do echo A; done < <(bash -c "stty -raw; echo -n $'\n\n\n'")
    A
    A
    A
    

    或者只是:

    ❯ stty raw; for i in {0..2}; do echo A; done
    A
     A
      A
    
    ❯ stty -raw; for i in {0..2}; do echo A; done
    A
    A
    A
    

    【讨论】:

      猜你喜欢
      • 2019-04-01
      • 2020-10-08
      • 2018-08-18
      • 1970-01-01
      • 2012-11-21
      • 2019-08-17
      • 2021-10-24
      • 2018-05-27
      • 1970-01-01
      相关资源
      最近更新 更多