为什么将docker pseudo-tty mangle输出到其他命令后输出?

时间:2019-02-15 12:43:00

标签: bash docker tty

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

使用CRLF选项运行时,Docker使用-t行尾。因此,这是我的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

这两个命令在读取-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是解决此问题的有效方法,但不能回答“为什么”。

1 个答案:

答案 0 :(得分:1)

当提供--tty选项时,似乎docker客户端将raw和stdout设置为原始模式。在setRawTerminal(streams)中定义的函数setupInput()中有一个对cli/command/container/hijack.go的调用,它将标准输入和标准输出都设置为原始模式(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