错误“输入设备不是 TTY”

Posted

技术标签:

【中文标题】错误“输入设备不是 TTY”【英文标题】:Error "The input device is not a TTY" 【发布时间】:2017-08-23 06:31:39 【问题描述】:

我正在从我的Jenkinsfile 运行以下命令。但是,我收到错误“输入设备不是 TTY”

docker run -v $PWD:/foobar -it cloudfoundry/cflinuxfs2 /foobar/script.sh

有没有办法在不使用交互模式的情况下从Jenkinsfile 运行脚本?

我基本上有一个名为 script.sh 的文件,我想在 Docker 容器中运行它。

【问题讨论】:

对于*nix,这里好像没有解决办法。 'docker exec -i' 不起作用,'-t' 也不起作用。 @rjurney 你有没有找到 docker exec 的解决方案?我试过 -i 和 -t 没有成功。 docker exec -it mycontainer bash certbot --apache -d www.website.com --email *********@gmail.com --agree-tos -n 【参考方案1】:

从您的 cli 中删除 -it 以使其非交互并删除 TTY。如果您也不需要,例如在 Jenkins 或 cron 脚本中运行你的命令,你应该这样做。

或者,如果您通过管道输入不是来自 TTY 的 docker 命令,则可以将其更改为 -i。如果您的命令行中有 xyz | docker ...docker ... <input 之类的内容,请执行此操作。

如果您想要 TTY 支持但输入设备上没有它,您可以将其更改为 -t。为检查 TTY 以启用日志中输出颜色格式的应用程序执行此操作,或者当您稍后使用适当的终端附加到容器时执行此操作。

或者,如果您需要一个交互式终端并且不在 Linux 或 MacOS 上的终端中运行,请使用不同的命令行界面。据报道 PowerShell 在 Windows 上包含此支持。


什么是 TTY?它是一个终端界面,支持转义序列、移动光标等,来自连接到大型机的愚蠢终端的旧时代。今天它由 Linux 命令终端和 ssh 接口提供。请参阅wikipedia article for more details。

要查看使用和不使用 TTY 运行容器的区别,请在没有 TTY 的情况下运行容器:docker run --rm -i ubuntu bash。在该容器内,使用apt-get update; apt-get install vim 安装vim。请注意缺少提示。对文件运行 vim 时,尝试在文件中移动光标。

【讨论】:

我将此命令与mysql -p 结合使用,但未指定密码。当只添加-i 时,密码提示永远不会出现。只需添加-t 就会出现提示,但它似乎根本没有读取输入(按字面意思打印而不是被提示隐藏),即使在点击返回时也是如此;只有 ctrl-c 可以结束它。以某种方式可以将mysql客户端与docker一起使用吗? 谢谢你!对于 docker-compose 用户,我想补充一点,我有一个类似的命令要运行 - 我想根据模式删除 redis 键 - 并且能够使用 docker-compose exec -T 命令执行此操作。来自docker-compose exec 的手册页:Disable pseudo-tty allocation. By default docker-compose exec allocates a TTY. 在 Windows 上使用 PowerShell 对我有用。【参考方案2】:

对于docker run 不要使用-it 标志

(如 BMitch 所说)

这并不完全符合您的要求,但对其他人也有用:

对于docker-compose exec 使用-T 标志!

-T 键 将帮助使用 docker-compose exec! 的人(它禁用伪 tty 分配)

例如:

docker-compose -f /srv/backend_bigdata/local.yml exec -T postgres backup

docker-compose exec -T mysql mysql -uuser_name -ppassword database_name < dir/to/db_backup.sql

【讨论】:

正是我所需要的。根据帮助: -T 禁用伪tty分配。默认情况下,docker-compose exec 分配一个 TTY。 在 mysql 虚拟机上运行 MySQL 数据库(使用上面建议的 -T):docker-compose exec -T mysql mysql -uuser_name -ppassword database_name &lt; dir/to/db_backup.sql 我希望我能再次投票给这个答案......【参考方案3】:

对于那些在 Windows 上遇到此错误和 git bash 的人,只需使用 -it 完美运行的 PowerShell。

【讨论】:

这没有回答问题。问题是关于 Jenkins 中的 docker,而不是 Windows 上的 git bash。 好吧。是的,而且它从未打算这样做。当您搜索此特定错误消息时,该问题会在 google 中弹出。我想,得到答案某处总比没有答案好。显然有些人觉得它很有用:) 将 Powershell 作为 TTY 进行 shell 操作的问题在于它不能正确传递箭头键,例如循环命令历史的向上箭头。除了这个缺点之外,效果很好。 如果你想继续使用Git Bash,见this answer on another question或the winpty answer below 它帮助了我,非常感谢你,我竖起大拇指。【参考方案4】:

如果你(和我一样)在 windows 上使用 git bash,你只需要把

winpty

在您的“码头线”之前:

winpty docker exec -it some_cassandra bash

【讨论】:

如何下载winpty 问之前有没有试过?我认为它是 Git 自带的(我的在里面 .../Git/usr/bin) 你说得对,它在C:\Program Files\Git\usr\bin\winpty.exe【参考方案5】:

为了让 docker 分配一个 TTY(-t 选项),当调用 docker run 时,您已经需要在一个 TTY 中。 Jenkins 不是在 TTY 中执行其作业。

话虽如此,您在 Jenkins 中运行的脚本您可能还想在本地运行。在这种情况下,分配一个 TTY 非常方便,这样您就可以在本地运行时发送 ctrl+c 之类的信号。

要解决此问题,请让您的脚本有选择地使用 -t 选项,如下所示:

test -t 1 && USE_TTY="-t" 
docker run $USE_TTY ...

【讨论】:

这个错误发生在我运行docker run…命令表单由git钩子触发的makefile任务时 这应该是公认的答案。它实际上以普遍适用的方式解决了问题【参考方案6】:

当使用“git bash”时,

1) 我执行命令:

docker exec -it 726fe4999627 /bin/bash

我有错误:

the input device is not a TTY.  If you are using mintty, try prefixing the command with 'winpty'

2) 然后,我执行命令:

winpty docker exec -it 726fe4999627 /bin/bash

我还有一个错误:

OCI runtime exec failed: exec failed: container_linux.go:344: starting container process caused "exec: \"D:/Git/usr/bin/
bash.exe\": stat D:/Git/usr/bin/bash.exe: no such file or directory": unknown

3) 第三,我执行:

winpty docker exec -it 726fe4999627 bash

成功了。

当我使用“powershell”时,一切正常。

【讨论】:

用 bash 将我的头撞到了墙上几个小时。切换到 Powershell,现在一切正常! (2) 失败,因为 winpty 将类 unix 文件路径的参数转换为 Windows 语言。要清楚地看到这一点:winpty echo "/foo/bar" 打印 C:/Program Files/Git/foo/bar 您可以使用MSYS_NO_PATHCONV=1关闭此行为【参考方案7】:

使用 docker-compose exec -T 通过 Jenkins 为我解决了这个问题

docker-compose exec -T containerName php script.php

【讨论】:

这项工作也在 github 上使用 docker compose 进行操作。谢谢【参考方案8】:

如果使用 Windows,请尝试使用 cmd ,对我来说它可以工作。检查docker是否启动。

【讨论】:

【参考方案9】:

下面显示的我的 Jenkins 管道步骤失败并出现同样的错误。

       steps 
            echo 'Building ...' 
            sh 'sh ./Tools/build.sh'
        

在我的“build.sh”脚本文件中,“docker run”命令在 Jenkins 作业执行时会输出此错误。但是,当脚本在 shell 终端中运行时,它工作正常。错误发生的原因是 -t 选项传递给 docker run 命令,该命令为我知道尝试分配终端,如果没有要分配的终端就会失败。

就我而言,我已将脚本更改为仅在可以检测到终端时才通过 -t 选项。这是修改后的代码:

DOCKER_RUN_OPTIONS="-i --rm"

# Only allocate tty if we detect one
if [ -t 0 ] && [ -t 1 ]; then
    DOCKER_RUN_OPTIONS="$DOCKER_RUN_OPTIONS -t"
fi

docker run $DOCKER_RUN_OPTIONS --name my-container-name  my-image-tag

【讨论】:

我喜欢你的回答,但如果没有检测到 TTY,我会默认使用 DOCKER_RUN_OPTIONS="--rm",因为 Jenkins 不需要 -i【参考方案10】:

我知道这不是直接回答手头的问题,而是针对使用 WSL 运行 Docker for windows 和 cmder 或 conemu 的任何人。

诀窍是不要使用安装在 Windows 上的 /mnt/c/Program Files/Docker/Docker/resources/bin/docker.exe 的 Docker,而是安装 ubuntu/linux Docker。值得指出的是,您不能从 WSL 中运行 Docker 本身,但您可以从 linux Docker 客户端连接到 Docker for windows。

在 Linux 上安装 Docker

sudo apt-get install apt-transport-https ca-certificates curl software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
sudo apt-get update
sudo apt-get install docker-ce

在端口 2375 上连接到 Docker for windows,这需要从 docker for windows 中的设置中启用。

docker -H localhost:2375 run -it -v /mnt/c/code:/var/app -w "/var/app" centos:7

或者设置 docker_host 变量,这将允许您省略 -H 开关

export DOCKER_HOST=tcp://localhost:2375

您现在应该能够与 tty 终端会话进行交互连接。

【讨论】:

【参考方案11】:

只要您不指定要挂载的卷,例如“.:/mountpoint”或“$pwd:/mountpoint”,winpty 就可以工作

我发现的最佳解决方法是使用 Visual Code Studio 中的 git-bash 插件,并使用终端启动和停止容器或 docker-compose。

【讨论】:

【参考方案12】:

在 Jenkins 中,我使用的是 docker-compose exec -T

例如:-

docker-compose exec -T app php artisan migrate

【讨论】:

【参考方案13】:

对于那些使用Pyinvoke 的人,请参阅this documentation,如果链接失效,我将在此处进行联合:

在 99% 的情况下,将 pty=True 添加到您的运行调用将使事情按您的预期工作。继续阅读为什么会这样(以及为什么 pty=True 不是默认设置)。

命令行程序通常会根据控制终端是否存在而改变行为;一个常见的例子是使用或不使用彩色输出。当输出的接收者是终端上的人时,您可能需要使用颜色、调整线长以匹配终端宽度等。

相反,当您的输出被发送到另一个程序(shell 管道、CI 服务器、文件等)时,颜色转义码和其他特定于终端的行为可能会导致不需要的垃圾。

Invoke 的用例涵盖上述两种情况——有时您只想直接显示数据,有时您只想将其捕获为字符串;通常你想要两者。正因为如此,没有“正确”的默认行为:使用伪终端 - 无论哪种方式,一些大块的用例都会带来不便。

对于不关心的用例,不带伪终端的直接调用更快更简洁,因此是默认设置。

【讨论】:

以上是关于错误“输入设备不是 TTY”的主要内容,如果未能解决你的问题,请参考以下文章

使用 grunt-shell 调用调用 docker run 的脚本时如何解决“输入设备不是 TTY”?

远程服务器返回错误: 404错误远程服务器返回错误:500错误 HttpWebResponse远程服务器返回错误:(404500) 错误。

Pig 安装错误:错误 pig.Main:错误 2998:未处理的内部错误

Informix 错误:发生了语法错误。错误代码:-201

我收到一个错误:“MetaMask - RPC 错误:错误:错误:[ethjs-rpc] rpc 错误与有效负载”

错误精灵错误跟踪器错误