为什么 docker pseudo-tty mangle 在通过管道传输到其他命令时输出?
Why does docker pseudo-tty mangle output when piped to other command?
当 docker 输出通过管道传输到其他命令时,为什么 docker 中的伪 tty 选项会修改输出?
当 运行 带有 -t
选项时,Docker 使用 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 循环(我希望两个输出相同)
❯ 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
是一个有效的解决方案,但不会回答 'why'。
似乎 docker 客户端在提供 --tty
选项时将 stdin 和 stdout 设置为原始模式。在 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
当 docker 输出通过管道传输到其他命令时,为什么 docker 中的伪 tty 选项会修改输出?
当 运行 带有-t
选项时,Docker 使用 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 循环(我希望两个输出相同)
❯ 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
是一个有效的解决方案,但不会回答 'why'。
似乎 docker 客户端在提供 --tty
选项时将 stdin 和 stdout 设置为原始模式。在 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