从stdin读取行并在其上运行命令

时间:2017-03-11 18:37:32

标签: bash shell gcloud

我正在尝试使用以下命令

gcloud compute instances list --format=json --regexp .*gluster.* | jq '.[].networkInterfaces[].networkIP' | tr -d '\"' | while read i; do gcloud compute ssh --zone $ZONE ubuntu@gluster-1 -- "sudo gluster peer probe $i && cat >> peers.txt"; done

基本上gcloud命令给出:

gcloud compute instances list --format=json --regexp .*gluster.* | jq '.[].networkInterfaces[].networkIP' | tr -d '\"'
10.128.0.2
10.128.0.3
10.128.0.4

但是只运行上面的命令似乎只能在主机的第一个ip上运行,给出警告

peer probe: success. Probe on localhost not needed

其他节点都没有连接。

注意: 奇怪地在第二个节点上运行gcloud命令连接到第一个节点,在第三个节点上运行根本没有做任何事情

除了第三个节点之外的所有节点上的peers.txt文件再次奇怪地只有后两个节点

ubuntu@gluster-1:~$ cat peers.txt
10.128.0.3
10.128.0.4

对循环中的值运行echo给出

gcloud compute instances list --format=json --regexp .*gluster.* | jq '.[].networkInterfaces[].networkIP' | tr -d '\"' | while read i; do echo ip: $i; done
ip: 10.128.0.2
ip: 10.128.0.3
ip: 10.128.0.4

2 个答案:

答案 0 :(得分:3)

管道进入循环没有任何问题(假设您不需要在当前shell中执行循环体)。但是,您不希望使用for循环来执行此类操作;有关详细信息,请参阅Bash FAQ 001。使用while循环。

gcloud compute instances list --format=json --regexp .*gluster.* | 
  jq -r '.[].networkInterfaces[].networkIP' |
  while IFS= read -r ipaddr; do
    echo "$ipaddr"
  done

(请注意,对-r使用jq选项,无需将输出通过管道传输到tr以删除双引号。)

您可能会遇到的问题是您在while循环中放置的命令从标准输入读取,该标准输入在read可以读取之前消耗来自管道的数据它。在这种情况下,您可以从/dev/null重定向标准输入:

gcloud compute instances list --format=json --regexp .*gluster.* | 
  jq -r '.[].networkInterfaces[].networkIP' |
    while IFS= read -r i; do
      gcloud compute ssh --zone $ZONE ubuntu@gluster-1 \
        -- "sudo gluster peer probe $i < /dev/null &&
      cat >> peers.txt"
    done

或者,使用进程替换来从不同的文件描述符中读取。

while IFS= read -r i <&3; do
  gcloud ...
done 3< <(gcloud compute instances .. | jq -r '...')

答案 1 :(得分:0)

使用for循环。

还了解到for循环不用于管道:)

for item in $(gcloud compute instances list --format=json --regexp .*gluster.* | jq '.[].networkInterfaces[].networkIP' | tr -d '\"'); do gcloud compute ssh --zone $ZONE ubuntu@gluster-1 -- "sudo gluster peer probe $item && echo $item >> peers.txt"; done