bash Docker 终端中的 Docker 行数在 docker 内更改

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/38786615/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 14:59:41  来源:igfitidea点击:

Docker number of lines in terminal changing inside docker

bashdockerterminaltput

提问by silgon

I would like to know how to change the following behavior. Let's say my terminal has 28lines. Then I use the following commands:

我想知道如何更改以下行为。假设我的终端有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

As you can see, even when all the results should be 28, when I'm calling the container as docker run --rm -it ubuntu:16.04 tput linesit always gives me 24 despite the size of my terminal. This is not only with the ubuntu container, I also tried with debian (docker run --rm -it debian tput lines) and I'm having the same result 24.

正如您所看到的,即使所有结果都应该是28,当我调用容器时,docker run --rm -it ubuntu:16.04 tput lines尽管我的终端有多大,它总是给我 24 。这不仅适用于 ubuntu 容器,我还尝试使用 debian ( docker run --rm -it debian tput lines) 并且得到了相同的结果 24。

The purpose of this is to use the mdp presentation toolwhich takes into account the lines in your terminal. When my implementation failed, I tried some other person's docker implementationbut I ran to the same error.

这样做的目的是使用mdp 演示工具,该工具考虑了终端中的行。当我的实现失败时,我尝试了其他人的docker 实现,但我遇到了同样的错误。

Here's my error in an image:

这是我在图像中的错误:

Docker number of lines in terminal changing inside docker

Docker 终端中的 Docker 行数在 docker 内更改

Does anyone has any idea what it could be and how can this be solved?

有谁知道它可能是什么以及如何解决?

采纳答案by VonC

Update Sept. 2018: check if docker 18.06 has the same issue (it should not, after moby/mobyissue 33794, and also moby/mobyissue 35407and PR 37172, part of the 18.06 release notes).

更新2018年9月:检查是否泊坞窗18.06有同样的问题(它不应该,以后moby/moby发行33794,以及moby/moby发行35407PR 37172,该部分18.06发行说明)。



2016:

2016年:

The Ubuntu Dockerfileincludes:

Ubuntu的Dockerfile包括:

CMD ["/bin/bash"]

That means the default ENTRYPOINTis sh -c(and I doubt tput lineworks well in a shsession, since tputuses terminfodatabase, which might be set only for bash in that image)

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

You could try overwrite ENTRYPOINTwith bash -cand check if that works better.

你可以尝试覆盖ENTRYPOINTbash -c和检查,如果是工作得更好。

That does not work from command line though:

但是,这在命令行中不起作用:

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

I will check the option of defining a custom image.

我将检查定义自定义图像的选项。

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

The result is the same though:

结果是一样的:

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

This however "works":

然而,这“有效”:

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

With:

和:

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

There might be a synchronization issue, as the same command does return 24 from time to time.

可能存在同步问题,因为同一命令会不时返回 24。

Actually, the following alwaysreturn "not 24" with:

实际上,以下总是返回“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

The OP silgonproposes in the comments:

OP silgon提出的意见

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


As BMitchcomments below:

正如BMitch在下面评论的那样

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.

鉴于 sleep 的成功,我怀疑 docker 使用 running 命令启动容器,一旦启动,客户端就会连接到正在运行的容器。通常需要几毫秒的时间。

That gave me another idea:

这给了我另一个想法:

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

A tput lineswithin an attached session works just fine.
(On the drmaealias, see "How to remove old and unused Docker images")

tput lines附加会话中的A工作正常。
(关于drmae别名,请参阅“如何删除旧的和未使用的 Docker 镜像”)



thajeztahadds in the comments:

thajeztah在评论中补充道:

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;

创建容器,然后以默认值 ( 80x24)启动,然后(when -it) 附加会话。
会话指定终端的大小;

See "Resize a container TTY" API.

请参阅“调整容器 TTY 大小”API。

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

For more, see docker issue 25450.
It is related to issue 10341 "Container create or start should accept height/width params". Aleksa Sarai (cyphar)adds (Sept. 2016):

有关更多信息,请参阅docker 问题 25450
它与问题 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.

这实际上在运行时规范中再次出现(opencontainers/runtime-spec PR 563)。
基本上,由于 Windows 需要在第一次启动时设置控制台大小的能力,我们最终可能会为所有平台添加它



The OP silgonpoints out to the code in api/client/container/run.go:

OP silgon指出在代码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()
}

With the logical question:

带着逻辑问题:

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

在 Linux 上也使用此属性并使用该值设置初始控制台大小是否有意义?

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

Kenfe-Micka?l Laventure ( mlaventure)就在它上面,一个新的补丁可以使它进入Docker 1.13

回答by Soorena

UPDATE

更新

you can now install goinsidecommand line tool with:

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

sudo npm install -g goinside

and go inside a docker container with a proper terminal size with:

并进入具有适当终端大小的 docker 容器,其中:

goinside docker_container_name


Logic behind goinside

goinside背后的逻辑

thanks to @VonC answerwe've got a solution for this problem with a simple bash snippet that we put in ~/.profile:

感谢@VonC 的回答,我们通过一个简单的 bash 代码片段解决了这个问题~/.profile

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

now you are able to get inside a docker container without terminal size issues with:

现在您可以进入 docker 容器,而不会出现终端大小问题:

$ goinside containername

$ goinside containername



rememberto source ~/.profilebefore using the goinsidefunction.

记得source ~/.profile使用前goinside的功能。



enabling autocompletion in bash

在 bash 中启用自动完成

(as it's shared in one of comments below) if you want to enable autocompletion for goinsideyou can use this snippet in .profile:

(因为它在下面的评论之一中共享)如果您想启用自动完成功能,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;


enabling autocompletion in zsh

在 zsh 中启用自动完成

if you are using zshas your default terminal you can use this snippet inside your ~/.zshrcfile:

如果您使用的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;

回答by NotSoShabby

A nice way to run bash inside the container without encountering line problems is here:

一个很好的方式,而不会遇到线路问题运行容器中使用bash是在这里

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

回答by Thomas Dickey

The comments about shversus terminfo are largely irrelevant. The relevant part (not clear in the given answer) is the way the command is executed. tputchecks three features in the following order (using setupterm):

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

  1. the size of the terminal from the terminfo database (many descriptions do not give this information, but with TERM=xterm, it is 24by 80),
  2. the actual number of lines if it can get that information from the operating system (i.e., the current window size), and
  3. the LINESand COLUMNSenvironment variables.
  1. terminfo 数据库中的终端大小(许多描述没有提供此信息,但是使用TERM=xterm,它是24x 80),
  2. 如果可以从操作系统获取该信息(即当前窗口大小),则为实际行数,以及
  3. LINESCOLUMNS环境变量。

A command which is run without an interactive shell couldbe executed in a way that precludes getting the current window size. For example, that is a feature of ssh(the -toption). Also, it would be possible (though pointless) for Docker to set the LINESand COLUMNSvariables.

在没有交互式 shell 的情况下运行的命令可以以一种排除获取当前窗口大小的方式执行。例如,这是ssh-t选项)的一个特征。此外,Docker 可以(尽管毫无意义)设置LINESCOLUMNS变量。

Either case (1) or (3) is enough to explain the behavior; introducing time-delays and races does not do that.

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

回答by Nico Toub

回答by silgon

I just tested with version Docker version 18.06.1-ce, build e68fc7a. It seems to have the same problem. However, one of the guys in the github issuegave a practical workaround:

我刚刚用 version 进行了测试Docker version 18.06.1-ce, build e68fc7a。它似乎有同样的问题。但是,github 问题中的一个人给出了一个实用的解决方法

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