【问题标题】:pseudo-terminal error will not be allocated because stdin is not a terminal - sudo伪终端错误将不会被分配,因为 stdin 不是终端 - sudo
【发布时间】:2014-03-10 02:09:14
【问题描述】:

还有其他主题相同的主题,但我的问题是独一无二的。我正在运行一个 bash 脚本,该脚本具有连接到远程服务器并在远程服务器上运行 sudo 命令的功能。我正在使用 ssh -t 选项来避免 requiretty 问题。只要不是从 while 循环中调用,有问题的代码行就可以正常工作。 while 循环基本上是从本地服务器上的一个 csv 文件读取并调用 checkAuthType 函数:

while read inputline
do
     ARRAY=(`echo $inputline | tr ',' ' '`)
     HOSTNAME=${ARRAY[0]}
     OS_TYPE=${ARRAY[1]}
     checkAuthType $HOSTNAME $OS_TYPE
     <more irrelevant code>
done < configfile.csv

这是位于脚本顶部的函数(在任何 while 循环之外):

function checkAuthType()
{
    if [ $2 == linux ]; then
       LINE=`ssh -t $1 'sudo grep "PasswordAuthentication" /etc/ssh/sshd_config | grep -v "yes\|Yes\|#"'`
    fi

    if [ $2 == unix ]; then
       LINE=`ssh -n $1 'grep "PasswordAuthentication" /usr/local/etc/sshd_config | grep -v "yes\|Yes\|#"'`
    fi
    <more irrelevant code>
}

因此,违规行是函数中包含 sudo 命令的行。我可以将命令更改为“sudo ls -l”之类的简单命令,但仍然会收到“stdin 不是终端”错误。我也尝试过“ssh -t -t”但无济于事。但是,如果我从 while 循环之外调用 checkAuthType 函数,它就可以正常工作。改变终端的while循环是什么,我该如何修复它?提前一千次感谢您。

【问题讨论】:

    标签: linux bash ssh scripting sudo


    【解决方案1】:

    BroSlow 使用不同文件描述符的方法似乎有效!由于read 命令从 fd 3 而不是 stdin 读取, sshsudo 仍然拥有或获得一个 tty/pty 作为标准输入。

    # simple test case
    while read line <&3; do
       sudo -k
       echo "$line"
       ssh -t localhost 'sudo ls -ld /'
    done 3<&- 3< <(echo 1; sleep 3; echo 2; sleep 3)
    

    【讨论】:

      【解决方案2】:

      我猜你正在使用 linux 进行测试。您应该尝试将 -n 标志添加到您的 (linux) ssh 命令中,以避免从标准输入读取 ssh - 因为它通常从标准输入读取,而 while 循环正在将它提供给您的 csv。

      更新

      您应该(通常)在使用 SSH 编写脚本时使用 -n 标志,并且在使用 while read 循环时,“预期行为”通常需要该标志。不过,这似乎不是这里的主要问题。 可能还有其他解决方案,但您可以尝试添加另一个 -t 标志以在 stdin 不是终端时强制分配伪 tty:

      ssh -n -t -t
      

      【讨论】:

      • 感谢您的回复。我为 Linux ssh 命令尝试了“ssh -n -t”和“ssh -t -n”,但我得到了同样的错误。
      • @Isaac 我怀疑这一点,但认为你可以试一试。请参阅我的更新答案! :)
      • 试过了。这对我的情况不起作用。不过,BroSlow 的解决方案奏效了。
      • @Isaac 太棒了!我用一个简单的“sudo ls”命令(有效)尝试了这个,但这并不是一个好的解决方案 - Broslow 的解决方案需要更多的“管道”,但更合适,显然也更安全:)
      【解决方案3】:

      尝试解决此问题的另一种选择是将文件重定向到不同的文件描述符并强制 从中读取。

      while read inputline <&3
      do
           ARRAY=(`echo $inputline | tr ',' ' '`)
           HOSTNAME=${ARRAY[0]}
           OS_TYPE=${ARRAY[1]}
           checkAuthType $HOSTNAME $OS_TYPE
           <more irrelevant code>
      done 3< configfile.csv
      

      【讨论】:

      • 这就是解决方案!我打算尝试将 csv 文件读入一个变量,而不是逐行读取它,然后使用 for 循环遍历数组值。不确定这是否可行,但这个解决方案要简单得多。非常感谢!
      猜你喜欢
      • 2011-10-30
      • 1970-01-01
      • 1970-01-01
      • 2018-07-16
      • 1970-01-01
      • 2015-06-26
      • 2019-08-13
      • 2011-06-07
      相关资源
      最近更新 更多