当管道传输到其他命令时,为什么docker伪tty mangle输出?

问题描述 投票:1回答:1

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

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

❯ 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 -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个回答
1
投票

当提供--tty选项时,似乎docker客户端在原始模式下设置stdin和stdout。在setRawTerminal(streams)中定义的函数setupInput()中调用cli/command/container/hijack.go,它在原始模式(github link)中设置stdin和stdout。

据我所知,这种原始模式然后传播回你正在使用的终端。您可以通过从以下示例中删除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
© www.soinside.com 2019 - 2024. All rights reserved.