Docker 终端内更改的行数 docker

Docker number of lines in terminal changing inside docker

我想知道如何更改以下行为。假设我的终端有 28 行。然后我使用以下命令:

$ tput lines # my terminal
28
$ docker run  --rm  -it ubuntu:16.04 tput lines  # docker container
24  ## WHY??
$ docker run  --rm  -it ubuntu:16.04 bash # docker container inside command
root@810effa2777c:/# tput lines
28

如您所见,即使所有结果都应该是 28,当我将容器称为 docker run --rm -it ubuntu:16.04 tput lines 时,尽管大小如此,它总是给我 24我的终端。这不仅适用于 ubuntu 容器,我还尝试使用 debian (docker run --rm -it debian tput lines),结果相同 24.

这个的目的是为了使用mdp presentation tool which takes into account the lines in your terminal. When my implementation failed, I tried some other person's docker implementation但是我运行同样的错误。

这是我在图像中的错误:

有没有人知道它可能是什么以及如何解决这个问题?

2018 年 9 月更新:检查 docker 18.06 是否有同样的问题 (it should not, after moby/moby issue 33794, and also moby/moby issue 35407 and PR 37172, part of the 18.06 release notes)。


2016:

Ubuntu Dockerfile包括:

CMD ["/bin/bash"]

这意味着默认的 ENTRYPOINTsh -c(我怀疑 tput linesh 会话中工作得很好,因为 tput 使用 terminfo 数据库,可能仅为该图像中的 bash 设置)

您可以尝试用 bash -c 覆盖 ENTRYPOINT 并检查是否效果更好。

虽然在命令行中不起作用:

docker run --entrypoint /bin/bash --rm  -it ubuntu:16.04 -i -c 'tput lines'
24

我会勾选定义自定义图像的选项。

FROM ubuntu:16.04
ENTRYPOINT ["/bin/bash", "-c"]

结果是一样的:

docker run --rm  -it u 'tput lines'
24

然而"works":

FROM ubuntu:16.04
ENTRYPOINT [ "/bin/bash" ]

与:

docker@default:/c/Users/vonc/prog/testsu$ docker run --rm  -it u -i -c 'ls; tput lines'
bin  boot  dev  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
48

可能存在同步问题,因为同一个命令有时 return 24。

其实下面总是return"not 24"有:

FROM ubuntu:16.04
ENTRYPOINT [ "/bin/bash", "-l", "-i", "-c" ]

docker run --rm  -it u -c 'sleep 0.1; ls; tput lines'
48

OP silgon proposes :

docker run --rm -it --entrypoint /bin/bash ubuntu:16.04 -c "sleep 0.1 && tput lines"

BMitch comments :

Given the success of sleep my suspicion is that docker spins up the container with the running command, and once up, the client attaches to the running container. Typically something that takes milliseconds.

这给了我另一个想法:

docker@default:/c/Users/vonc/prog/testsu$ 
docker run --entrypoint='/bin/bash' --name ub -d -it ubuntu:16.04
  0d9b8783afbb5e3ff4232da071d3f357985351ea1ce4d142bf6617ac456fb76b
docker@default:/c/Users/vonc/prog/testsu$ 
d attach ub
  root@0d9b8783afbb:/# tput lines
  48
  root@0d9b8783afbb:/# exit
exit
docker@default:/c/Users/vonc/prog/testsu$ drmae
0d9b8783afbb5e3ff4232da071d3f357985351ea1ce4d142bf6617ac456fb76b

附加会话中的 tput lines 工作正常。
(关于 drmae 别名,参见“”)


thajeztah adds :

the container is created, then started with the defaults (80x24), and after that (when -it), a session is attached.
The session is specifying the size of the terminal;

参见“Resize a container TTY”API。

 DEBU[0244] Calling POST /v1.25/containers/c42fd5c4eb79c06fd7f9912b8359022f7d93887afbb33b57a67ed8bb7bfee4‌​3a/resize?h=46&w=221 

有关更多信息,请参阅 docker issue 25450
它与 issue 10341 "Container create or start should accept height/width params". Aleksa Sarai (cyphar) 添加相关(2016 年 9 月):

This has actually popped up again inside the runtime-spec (opencontainers/runtime-spec PR 563).
Basically, since Windows requires the ability to set the console size on first start, we might end up adding it for all platforms.


OP silgon points out to the code in api/client/container/run.go:

// Telling the Windows daemon the initial size of the tty during start makes
// a far better user experience rather than relying on subsequent resizes
// to cause things to catch up.
if runtime.GOOS == "windows" {
    hostConfig.ConsoleSize[0], hostConfig.ConsoleSize[1] = dockerCli.GetTtySize()
}

逻辑问题:

would it make sense to use this property on Linux as well, and set the initial console size using that value?

Kenfe-Mickaël Laventure (mlaventure) is on it, and a new patch could make it to Docker 1.13.

关于 sh 与 terminfo 的评论在很大程度上是无关紧要的。相关部分(在给定的答案中不清楚)是命令的执行方式。 tput 按以下顺序检查三个特征(使用 setupterm):

  1. 来自terminfo数据库的终端大小(很多描述没有给出这个信息,但是用TERM=xterm,它是24 by 80),
  2. 实际行数,如果它可以从操作系统获取该信息(即当前window大小),并且
  3. LINESCOLUMNS 环境变量。

一个 运行 没有交互式 shell 的命令可以 以排除获取 当前 window尺寸。例如,这是 ssh-t 选项)的一个特性。此外,Docker 可以(尽管毫无意义)设置 LINESCOLUMNS 变量。

情况 (1) 或 (3) 都足以解释该行为;引入时间延迟和比赛并不能做到这一点。

更新

您现在可以安装 goinside 命令行工具:

sudo npm install -g goinside

然后进入具有适当终端尺寸的 docker 容器:

goinside docker_container_name

goinside 背后的逻辑

多亏了 ,我们通过一个简单的 bash 片段解决了这个问题,我们将其放入 ~/.profile:

goinside(){
    docker exec -it  bash -c "stty cols $COLUMNS rows $LINES && bash";
}
export -f goinside

现在您可以进入 docker 容器而不会出现终端尺寸问题:

$ goinside containername


记住source ~/.profile,然后再使用goinside功能。


在 bash

中启用自动完成

(因为它在下面的评论之一中共享)如果您想为 goinside 启用自动完成,您可以在 .profile:

中使用此代码段
goinside(){
    docker exec -it  bash -c "stty cols $COLUMNS rows $LINES && bash";
}
_goinside(){
    COMPREPLY=( $(docker ps --format "{{.Names}}" -f name=) );
}
complete -F _goinside goinside;
export -f goinside;

在 zsh 中启用自动完成

如果您使用 zsh 作为默认终端,您可以在 ~/.zshrc 文件中使用此代码段:

autoload bashcompinit
bashcompinit
goinside(){
    docker exec -it  bash -c "stty cols $COLUMNS rows $LINES && bash";
}
_goinside(){
    COMPREPLY=( $(docker ps --format "{{.Names}}" -f name=) );
}
complete -F _goinside goinside;
export goinside;

已在 docker 18.06 中修复:https://github.com/moby/moby/issues/33794#issuecomment-406814439

我刚用 Docker version 18.06.1-ce, build e68fc7a 版本测试过。它似乎有同样的问题。但是,github issue gave a practical workaround 中的一个人:

docker run --rm -it -e COLUMNS=$COLUMNS -e LINES=$LINES -e TERM=$TERM -it ubuntu:16.04 tput lines

在容器内 运行 bash 而不会遇到线路问题的一个好方法是 here:

docker exec -e COLUMNS="`tput cols`" -e LINES="`tput lines`" -ti container bash