为什么 while 循环会跳过并只读取第一行?

为什么 while 循环会跳过并只读取第一行?
$ ls
testscript.sh  testservers.txt
$ cat testservers.txt 
serverA IMM 10.2.3.4    USERID  PASSW0RD
serverB IMM 10.2.3.5    USERID  PASSW0RD
$ 
$ 
$ cat testscript.sh 
#!/bin/bash

# test them..
egrep -vi '^#|^$' testservers.txt | while read ONELINE; do
    # variables..
    SERVER=`echo "$ONELINE" | awk 'BEGIN {FS="\t"} {print $1}'`
    RSATYPE=`echo "$ONELINE" | awk 'BEGIN {FS="\t"} {print $2}'`
    IP=`echo "$ONELINE" | awk 'BEGIN {FS="\t"} {print $3}'`
    USER=`echo "$ONELINE" | awk 'BEGIN {FS="\t"} {print $4}'`
    PWD=`echo "$ONELINE" | awk 'BEGIN {FS="\t"} {print $5}'`

if [ "$RSATYPE" = "IMM" ]; then
    # main testing part for IMM
        timeout 5 tsocks nc -z -w 3 "${IP}" 80 > /dev/null 2>&1; if [[ $? -eq 0 ]]; 
            then WEBINTOK="true"
            else WEBINTOK="false"
            fi

        IMMSSH=`(timeout 5 tsocks sshpass -p "${PWD}" ssh -l "${USER}" -o StrictHostKeyChecking=no "${IP}" exit)`
        if echo "${IMMSSH}" | grep -q "tty name check failed"; then 
            ${WEBINTOK} && echo -e "${SERVER} ${USER} - OK" || echo -e "${SERVER} ${USER} - ERROR"
        else 
            ${WEBINTOK} && echo -e "${SERVER} ${USER} - ERROR" || echo -e "${SERVER} ${USER} - ERROR"
        fi
fi

done
$ 
$ bash testscript.sh 
serverA USERID - OK
$ 

我们的问题:为什么脚本只读取第一行?它假设读取 testservers.txt 中的所有行..

更新:testservers.txt 有正确的选项卡,我真的不认为这是问题所在:\

$ cat -vte testservers.txt
serverA^IIMM^I10.2.3.4^IUSERID^IPASSW0RD$
serverB^IIMM^I10.2.3.5^IUSERID^IPASSW0RD$
$ 

答案1

你有:

egrep... | while read ...; do
    ...
    ... ssh $IP exit...
    ...
  done

ssh连接到远程主机并运行远程命令并向其发送从其标准输入读取的内容(除非传递了该-n选项)

在这种情况下,ssh的 stdin 是来自 的管道,从中读取egrep相同的管道。read

因此,它通常会读取 的所有输出egrep并将其发送到exit上的命令$IP(远程 shell 或exit不读取它,但ssh会读取它)。

nc是另一个命令,它读取其标准输入以通过其建立的连接发送,但在传递选项时则不会-z像此处那样。

要避免此问题,请使用-n选项ssh或将ssh的 stdin 从/dev/null( ssh < /dev/null...) 重定向。

答案2

斯蒂芬有正确的答案。我主要评论的是风格。

为了减少你必须读取变量的工作,而不是

while read ONELINE; do
    # variables..
    SERVER=`echo "$ONELINE" | awk 'BEGIN {FS="\t"} {print $1}'`
    RSATYPE=`echo "$ONELINE" | awk 'BEGIN {FS="\t"} {print $2}'`
    IP=`echo "$ONELINE" | awk 'BEGIN {FS="\t"} {print $3}'`
    USER=`echo "$ONELINE" | awk 'BEGIN {FS="\t"} {print $4}'`
    PWD=`echo "$ONELINE" | awk 'BEGIN {FS="\t"} {print $5}'`
    # ...

做这个

while IFS=$'\t' read SERVER RSATYPE IP USER PWD; do
    # ...

而不是写作

some command 
if [[ $? -eq 0 ]]; then
    do_this
else
    do_that
fi

if some command; then
    do_this
else
    do_that
fi

由于这是一个 bash 脚本,而不是

echo "${IMMSSH}" | grep -q "tty name check failed"

grep -q "tty name check failed" <<<"${IMMSSH}"

另外,改掉使用 ALL_CAPS_VARNAMES 的习惯:有一天,PATH当您找不到任何外部命令时,您会使用它,然后想知道为什么您的脚本被破坏了。

相关内容