【问题标题】:"stdin: is not a tty" from cronjob来自 cronjob 的“stdin:不是 tty”
【发布时间】:2014-11-27 06:11:33
【问题描述】:

每次执行特定的 cronjob 时都会收到以下邮件。当我直接调用它甚至从 cron 调用时,被调用的脚本运行良好。所以我得到的消息不是一个实际的错误,因为脚本完全按照它应该做的事情。

这是 cron.d 条目:

* *     * * *     root   /bin/bash -l -c "/opt/get.sh > /tmp/file"

还有 get.sh 脚本本身:

#!/bin/sh

#group and url
groups="foo"

url="https://somehost.test/get.php?groups=${groups}"

# encryption
pass='bar'
method='aes-256-xts'
pass=$(echo -n $pass | xxd -ps | sed 's/[[:xdigit:]]\{2\}/&/g')

encrypted=$(wget -qO- ${url})
decoded=$(echo -n $encrypted | awk -F '#' '{print $1}')
iv=$(echo $encrypted | awk -F '#' '{print $2}' |base64 --decode | xxd -ps | sed 's/[[:xdigit:]]\{2\}/&/g')

# base64 decode input and save to file
output=$(echo -n $decoded | base64 --decode | openssl enc -${method} -d -nosalt -nopad -K ${pass} -iv ${iv})

if [ ! -z "${output}" ]; then
        echo "${output}"
else
        echo "Error while getting information"
fi

当我不使用 bash -l 语法时,脚本会在 wget 过程中挂起。所以我的猜测是它与wget有关并将输出放入stdout。但我不知道如何解决它。

【问题讨论】:

  • 是的,我确实使用通过 http_proxy 变量设置的代理。
  • 哦,等等,我想我们已经到了这里。我通过 /etc/profile.d 中的文件设置代理,该文件包含在 /etc/profile 中。也许这在“正常” cronjob 调用期间不可用?
  • 确保当您的 bash(用户 root)不是登录 shell 时设置该变量。

标签: linux bash cron crontab


【解决方案1】:

在您的 .profile 中更改

mesg n

if `tty -s`; then
  mesg n
fi

【讨论】:

  • 这里是这个解决方案的解释:你必须在使用mesg之前检查stdin是终端。
  • .profile 在哪里?如果它是主目录中的那个,那么我的文件中没有mesg n
【解决方案2】:

您实际上有两个问题。

  1. 为什么会打印stdin: is not a tty

此警告消息由bash -l 打印。 -l (--login) 选项要求 bash 启动登录 shell,例如通常在您输入密码时启动。在这种情况下,bash 期望它的 stdin 是一个真正的终端(例如,isatty(0) 调用应该返回 1),如果它是由 cron 运行的,则它不是真的——因此这个警告。

另一种重现此警告的简单方法,也是非常常见的方法,是通过ssh 运行此命令:

$ ssh user@example.com 'bash -l -c "echo test"'
Password:
stdin: is not a tty
test

这是因为ssh 在使用命令作为参数调用时没有分配终端(在这种情况下,应该使用ssh-t 选项来强制分配终端)。

  1. 为什么没有-l 就不行?

正如@Cyrus 在 cmets 中正确指出的那样,bash 在启动时加载的文件列表取决于会话的类型。例如。对于登录 shell,它将加载 /etc/profile~/.bash_profile~/.bash_login~/.profile(参见手册中的 INVOCATION bash(1)),而对于非登录 shell,它将仅加载 ~/.bashrc。看来您仅在为登录 shell 加载的文件之一中定义了您的 http_proxy 变量,而不是在 ~/.bashrc 中。您将其移至 ~/.wgetrc 并且它是正确的,但您也可以在 ~/.bashrc 中定义它并且它会起作用。

【讨论】:

    【解决方案3】:

    我最终将代理配置放在 wgetrc 中。现在不再需要在登录 shell 上执行脚本了。

    这不是对实际问题的真正答案,但它解决了我的问题。

    如果您遇到此问题,请检查您是否按预期设置了所有环境变量。感谢 Cyrus 为我指明了正确的方向。

    【讨论】:

      猜你喜欢
      • 2017-04-02
      • 1970-01-01
      • 2015-04-01
      • 2017-12-20
      • 1970-01-01
      • 2017-06-13
      • 1970-01-01
      • 2010-11-18
      • 1970-01-01
      相关资源
      最近更新 更多