while 循环读取文件过早结束 [英] while loop to read file ends prematurely
问题描述
最终目标是让我的 bash 脚本在多个服务器上执行命令.我几乎已经设置好了.我的 SSH 身份验证工作正常,但是这个简单的 while 循环正在杀死我.当我执行 while 循环,读取我的文件以获取主机名时,当我运行
时它工作正常<块引用>ssh $HOST "uname -a"
但是当我尝试运行另一个 ssh 命令时,
<块引用>ssh $HOST "oslevel -s"
while 循环提前结束!我想不通.为什么 while read do 循环可以在第一个命令下运行得很好,但在添加第二个命令时却没有?
我有一个名为 hosts.list 的简单文本文件,它有 4 个主机名,每行一个.
$ cat hosts.listpcced1bip04pcced1bit04pcced1bo02pcced1bo04$ cat getinfo.bash#!/bin/bash设置 -x读主机时做回声 $HOSTssh $HOST "uname -a"#ssh $HOST "oslevel -s"回声"完成<主机列表`
当它运行时,它工作正常.它逐行遍历文件并获取 "uname -a"
的结果.所以一切都很好,对吧?(抱歉,我打开了 set -x
).
$ ./getinfo.bash+ 读取主机+ 回声 pcced1bip04pcced1bip04+ ssh pcced1bip04 'uname -a'AIX pcced1bip04 1 6 0001431BD400+ 回声 ''+ 读取主机+ 回声 pcced1bit04pcced1bit04+ ssh pcced1bit04 'uname -a'AIX pcced1bit04 1 6 0001431BD400+ 回声 ''+ 读取主机+ 回声 pcced1bo02pcced1bo02+ ssh pcced1bo02 'uname -a'AIX pcced1bo02 1 6 0009FE2AD400+ 回声 ''+ 读取主机+ 回声 pcced1bo04pcced1bo04+ ssh pcced1bo04 'uname -a'AIX pcced1bo04 1 6 0009FE2AD400+ 回声 ''+ 读取主机$
当我启用线路时出现问题 [ssh $HOST "oslevel -s"].当我这样做时,脚本只读取文件的第一行,然后停止.为什么不转到其他线路上?
$ ./getinfo.bash+ 读取主机+ 回声 pcced1bip04pcced1bip04+ ssh pcced1bip04 'uname -a'AIX pcced1bip04 1 6 0001431BD400+ ssh pcced1bip04 'oslevel -s'6100-06-02-1044+ 回声 ''+ 读取主机$
如果我的脚本有问题,为什么在 while 循环中仅使用 [ssh $HOST "uname -a"]
就可以正常工作?
如果您在循环内运行从 stdin 读取的命令(例如 ssh
),您需要确保:>
- 您的循环没有遍历标准输入
- 您的命令的标准输入已重定向:
...否则,该命令可能会消耗用于循环的输入,从而导致循环结束.
前者:
while read -u 5 -r hostname;做ssh "$主机名" ...完成 5<文件
...使用 bash 4.1 或更高版本,可以使用自动文件描述符分配重写,如下所示:
while read -u "$file_fd" -r hostname;做ssh "$主机名" ...完成 {file_fd}
后者:
while read -r hostname;做ssh "$hostname" ... </dev/null完成<文件
...也可以,仅对于 ssh,也可以用 -n
参数近似(它也从 /dev/null
重定向 stdin):>
while read -r hostname;做ssh -n "$hostname"完成<文件
The eventual goal is to have my bash script execute a command on multiple servers. I almost have it set up. My SSH authentication is working, but this simple while loop is killing me. When I execute the while loop, reading my file for host names, it works fine when I run a
ssh $HOST "uname -a"
but when I attempt to run another ssh command,
ssh $HOST "oslevel -s"
the while loop ends early! I can't figure it out. Why would the while read do loop run perfectly fine with the first command, but not when the second is added?
I have a simple text file called hosts.list that has 4 hostnames, one per line.
$ cat hosts.list
pcced1bip04
pcced1bit04
pcced1bo02
pcced1bo04
$ cat getinfo.bash
#!/bin/bash
set -x
while read HOST
do
echo $HOST
ssh $HOST "uname -a"
#ssh $HOST "oslevel -s"
echo ""
done < hosts.list`
When it runs, it works fine. It goes through the file, line by line and gets the results of "uname -a"
. So everything is fine, right? (Sorry, but I turned on set -x
).
$ ./getinfo.bash
+ read HOST
+ echo pcced1bip04
pcced1bip04
+ ssh pcced1bip04 'uname -a'
AIX pcced1bip04 1 6 0001431BD400
+ echo ''
+ read HOST
+ echo pcced1bit04
pcced1bit04
+ ssh pcced1bit04 'uname -a'
AIX pcced1bit04 1 6 0001431BD400
+ echo ''
+ read HOST
+ echo pcced1bo02
pcced1bo02
+ ssh pcced1bo02 'uname -a'
AIX pcced1bo02 1 6 0009FE2AD400
+ echo ''
+ read HOST
+ echo pcced1bo04
pcced1bo04
+ ssh pcced1bo04 'uname -a'
AIX pcced1bo04 1 6 0009FE2AD400
+ echo ''
+ read HOST
$
The problem occurs when I enable the line [ssh $HOST "oslevel -s"]. When I do, the script only reads the first line of the file, and then stops. Why won't it go onto the other lines?
$ ./getinfo.bash
+ read HOST
+ echo pcced1bip04
pcced1bip04
+ ssh pcced1bip04 'uname -a'
AIX pcced1bip04 1 6 0001431BD400
+ ssh pcced1bip04 'oslevel -s'
6100-06-02-1044
+ echo ''
+ read HOST
$
If I had a problem with my script, why would it be working perfectly fine with just the [ssh $HOST "uname -a"]
in the while loop?
If you run commands which read from stdin (such as ssh
) inside a loop, you need to ensure that either:
- Your loop isn't iterating over stdin
- Your command has had its stdin redirected:
...otherwise, the command can consume input intended for the loop, causing it to end.
The former:
while read -u 5 -r hostname; do
ssh "$hostname" ...
done 5<file
...which, using bash 4.1 or newer, can be rewritten with automatic file descriptor assignment as so:
while read -u "$file_fd" -r hostname; do
ssh "$hostname" ...
done {file_fd}<file
The latter:
while read -r hostname; do
ssh "$hostname" ... </dev/null
done <file
...can also, for ssh alone, can also be approximated with the -n
parameter (which also redirects stdin from /dev/null
):
while read -r hostname; do
ssh -n "$hostname"
done <file
这篇关于while 循环读取文件过早结束的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!