关于linux:不会分配伪终端错误,因为stdin不是终端 – sudo

pseudo-terminal error will not be allocated because stdin is not a terminal - sudo

有其他线程具有相同的主题,但我的问题是唯一的。我正在运行一个bash脚本,该脚本具有一个对远程服务器进行ssh的函数,并在远程服务器上运行sudo命令。我使用ssh-t选项来避免Requiretty问题。只要不在while循环中调用,违规代码行就可以正常工作。while循环基本上从本地服务器上的csv文件读取并调用checkauthtype函数:

1
2
3
4
5
6
7
8
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循环之外):

1
2
3
4
5
6
7
8
9
10
11
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循环是怎么回事?如何修复它?提前一千次谢谢你。


另一个解决这个问题的方法是将文件重定向到另一个文件描述符,并强制从中读取。

1
2
3
4
5
6
7
8
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


Broslow使用不同文件描述符的方法似乎有效!由于read命令读取的是fd 3而不是stdin,ssh因此sudo仍然有或得到一个tty/pty作为stdin。

1
2
3
4
5
6
# 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)


我猜你是在用Linux测试。您应该尝试将-n标志添加到(linux)ssh命令中,以避免从stdin读取ssh,因为它通常在循环为其提供csv时从stdin读取。

更新

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

1
ssh -n -t -t