Bash Shell 逐行读取文件

1. 问题

先看有问题的代码:

#!/bin/bash
cat file.txt | while read eachline ; do
        echo $eachline
done

上例中,while代码块的输入流已经被管道符重定向至cat的输出,

所以如果在while代码块内,有sed、awk、ssh 等命令时,会在第一次循环时,一次性读取输入流内容的所有行。

这样read命令在第二次运行时,输入流的内容已经是空的,read就读取不到内容,从而结束循环。

2. 解决方法

为了避免上面的问题,可以参考这样的处理方式:

假如,/etc/hosts的内容有

192.168.12.6   host_a
192.168.12.9  host_b
192.168.12.18  host_c
192.168.12.19  host_d

用这段代码处理:

cat /etc/hosts | grep host | while read v1 v2
do
exec 8<& 0 0< /dev/null
ssh $v2 "hostname"
exec 0<& 8 8<& -
done

运行以上代码后,输出结果为:

host_a
host_b
host_c
host_d

3. 原理

FD=文件标示符(File Descriptor)

exec 8<& 0 0< /dev/null 这句会将FD=8的输入重定向到FD=0所使用的输入设备,然后将FD=0的输入重定向到/dev/null。

这样,ssh就不会影响到read在下一次要读取的内容。

exec 0<& 8 8<& - 这句会将FD=0的输入重定向到FD=8所使用的输入设备(也就是cat的输出内容),然后关闭FD=8的输入,使其他程序可以使用FD=8。

标签:ShellBash 发布于:2019-10-28 16:04:24