bash Bash而读取循环提前中断
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/346445/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Bash while read loop breaking early
提问by Foo Bah
I've been banging my head against for wall for a while with this one.
我一直在用这个头撞墙一段时间。
I want to SSH into a set of machines and check whether they are available (accepting connections and not being used). I have created a small script, tssh, which does just that:
我想通过 SSH 连接到一组机器并检查它们是否可用(接受连接但未被使用)。我创建了一个小脚本 tssh,它就是这样做的:
#!/bin/bash
host=
timeout=${2:-1}
ssh -qo "ConnectTimeout $timeout" $host "[ \`who | cut -f1 | wc -l \` -eq 0 ] && exit 0 || exit 1"
This script works correctly. Returning 255 if there was a connection problem, 1 if the machine is busy and 0 if everything is good. If anyone knows a better way to do this please let me know.
此脚本正常工作。如果存在连接问题,则返回 255,如果机器忙则返回 1,如果一切正常则返回 0。如果有人知道更好的方法来做到这一点,请告诉我。
So next I try and call tssh on my set of machines using a while read loop, and this is where it all goes wrong. The loop exits as soon as tssh returns 0 and never completes the full set.
所以接下来我尝试使用 while 读取循环在我的一组机器上调用 tssh,这就是一切出错的地方。一旦 tssh 返回 0 并且永远不会完成完整集,循环就会退出。
while read nu ; do tssh "MYBOXES$nu" ; done < <(ruby -e '(0..20).each { |i| puts i }')
At first I thought this was a subshell problem but apparently not. Any help, along with comments on style/content, would be much appreciated! I know I'm going to kick myself when I find out why...
起初我认为这是一个子外壳问题,但显然不是。任何帮助,以及对样式/内容的评论,将不胜感激!我知道当我发现原因时我会踢自己...
采纳答案by Paul Tomblin
Don't know if it would help, but a cleaner way of writing that would be
不知道它是否会有所帮助,但更简洁的写作方式是
for nu in `ruby -e '(0..20).each { |i| puts i}'`; do
tssh "MYBOXES$nu"
done
回答by
Chris is correct. The source of the loop breaking was SSH using stdin, however guns is correct in is usage of a looping methodology.
克里斯是对的。循环中断的来源是使用标准输入的 SSH,但是 guns 在使用循环方法方面是正确的。
If you are looping through input (a file with a list of hostnames for example), and calling SSH, you need to pass the -n parameter, otherwise your loop based on input will fail.
如果您循环输入(例如带有主机名列表的文件)并调用 SSH,则需要传递 -n 参数,否则基于输入的循环将失败。
while read host; do
ssh -n $host "remote command" >> output.txt
done << host_list_file.txt
回答by Foo Bah
In the construct
在构造
something |
while read x; do
ssh ...
done
the standard input as seen by the while loop is the output of something
.
while 循环所看到的标准输入是 的输出something
。
The default behavior of ssh
is to read standard input. This allows you to do things like
的默认行为ssh
是读取标准输入。这使您可以执行以下操作
cat id_rsa.pub | ssh new_box "cat - >> ~/.ssh/authorized_keys"
Now, with that being said, when the first value is read, the first ssh command will read the entire input from something
. Then, by the time ssh finishes, there is no output left, and read
stops.
现在,话虽如此,当读取第一个值时,第一个 ssh 命令将从something
. 然后,到 ssh 完成时,没有输出,并read
停止。
The fix is ssh -n ...
e.g.
修复是ssh -n ...
例如
cat /etc/hosts | awk '{print }' | while read x; do
ssh -n $x "do_something_on_the_machine"
done
回答by Foo Bah
I ran into this today -- rsh and/or ssh can break a while read loop due to it using stdin. I put a -n into the ssh line which stops it from trying to use stdin and it fixed the problem.
我今天遇到了这个问题——rsh 和/或 ssh 可能会因为使用 stdin 而中断 while 读取循环。我将 -n 放入 ssh 行,阻止它尝试使用 stdin 并解决了问题。
回答by rouble
Most of the answers are specific to ssh. Other commands also hiHyman stdin and do not have a -n option. This should address any other commands. This should also work for ssh.
大多数答案都特定于 ssh。其他命令也会劫持 stdin 并且没有 -n 选项。这应该解决任何其他命令。这也适用于 ssh。
while read x; do
# Make sure command does not hiHyman stdin
echo "" | command $x
done < /path/to/some/file
回答by Johannes Schaub - litb
I'm also unsure about why it fails, but i like xargs
and seq
:
我也不确定它为什么会失败,但我喜欢xargs
和seq
:
seq 0 20 | xargs -n1 tssh MYBOXES
回答by guns
As Kaii mentioned, it's really overkill to call ruby or seq (which won't work on BSD or OSX machines) just to output a range of numbers. If you're happy with using bash you can:
正如 Kaii 所提到的,仅仅为了输出一系列数字而调用 ruby 或 seq(这不适用于 BSD 或 OSX 机器)真的有点矫枉过正。如果您对使用 bash 感到满意,您可以:
for i in {0..20}; do
# command
done
I believe this should work for bash 2.05b and up.
我相信这应该适用于 bash 2.05b 及更高版本。
回答by Kevin Mullet
talk about a "robbing Peter to pay Paul" problem. I'd been struggling for hours to figure out why my ssh was killing my something|while read loop.
讲一个“抢彼得付保罗”的问题。我一直在努力弄清楚为什么我的 ssh 会杀死我的东西|while read 循环。
Another way to stick with a while read loop and keep your ssh at the same time is to use the "-n" switch to make STDIN on ssh /dev/null. Works like a charm for me:
坚持使用 while 读取循环并同时保持 ssh 的另一种方法是使用“-n”开关在 ssh /dev/null 上创建 STDIN。对我来说就像一个魅力:
#!/bin/bash
[...]
something|while read host
do
ssh -nx ${host} fiddleAround
done
(I tend to always use the "-x" too to avoid wasting time negotiating X in a tunnel.)
(我也倾向于总是使用“-x”以避免浪费时间在隧道中协商 X。)
回答by Kaii
i cant believe it was the result of 0 that broke your loop, you can test against this by replacing your tssh command in the loop with "/bin/true" which also returns 0.
我不敢相信这是 0 的结果破坏了您的循环,您可以通过将循环中的 tssh 命令替换为“/bin/true”(也返回 0)来对此进行测试。
regarding style i dont understand why a simple looping shell script needs ruby, perl, seq or jot or any other binary that is not on my *BSD.
关于样式,我不明白为什么一个简单的循环 shell 脚本需要 ruby、perl、seq 或 jot 或任何其他不在我的 *BSD 上的二进制文件。
you can alternatively use the shells builtin for loop construct, which works at least in ksh, bash:
您也可以使用内置的 shell for 循环构造,它至少适用于 ksh、bash:
for ((i=0; $i<=20; i++)); do
tssh "MYBOXES$i"
done