bash - 为什么当通过管道传输到其他命令时 docker 伪 tty 会破坏输出?
问题描述
当 docker 输出通过管道传输到其他命令时,为什么 docker 中的伪 tty 选项会修改输出?
Docker在使用选项CRLF
运行时使用行尾。-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
两个命令都通过管道传输到 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
非交互式脚本是一个有效的解决方案,但不回答“为什么”。
解决方案
提供选项时,docker客户端似乎将标准输入和标准输出设置为原始模式--tty
。调用in 中定义setRawTerminal(streams)
的函数,它将标准输入和标准输出设置为原始模式(github链接)。setupInput()
cli/command/container/hijack.go
据我所知,这种原始模式会传播回您正在使用的终端。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
推荐阅读
- php - PHP 对象树到嵌套复杂头表
- generics - 当当前函数不能内联(但我们有反射)时,如何将具体参数传递给其他函数?
- webpack - sass-loader 在 webpack 中很慢
- flutter - 如何将这个 dart 类放在一起,以便我可以在代码的不同部分使用它
- r - 无法在带有 cairo_pdf 的表达式中保存带有变音符号的 ggplot
- api - 如何在 azure API 管理服务中添加 API,它不是“托管的 Azure API”
- spring-boot - 嵌套异常是 io.lettuce.core.RedisCommandExecutionException: ERR no such key
- java - 有没有办法检查对象的属性是否有值?
- php - 检查状态的响应标头 - HTTP 状态代码
- python - 对于大小为 3 的轴 0,Python 索引 3 超出范围