首頁 > 軟體

shell中while迴圈的陷阱

2020-06-16 17:09:06

在寫while迴圈的時候,發現了一個問題,在while迴圈內部對變數賦值、定義變數、陣列定義等等環境,在迴圈外面失效。

一個簡單的測試指令碼如下:

#!/bin/bash
echo "abc xyz" | while read line
do
    new_var=$line
done
echo new_var is null: $new_var?

執行結果證明,$new_var的結果是空值。在google上查了查,才發現問題出在管道上。

先看看下面的內容。

while迴圈的寫法有好幾種,它的語法結構為:

while test_cmd_list; do cmd_list; done

但更經常地,while迴圈更多地用於讀取標准輸入的內容來實現迴圈。有以下幾種寫法:

寫法一:使用管道傳遞內容,這是用的最多、但卻最爛的寫法

echo "abc xyz" | while read line  

do 

    ...

done

寫法二:

while read line

do

    ...

done <<< "abc xyz"

寫法三:從檔案中讀取內容

while read line

do

    ...

done </path/filename

方法四:採用進程替換

while read var

do

    ...

done < <(cmd_list)          

方法五:改變標準輸入

exec <filename

while read var

do

    ...

done        

儘管寫法有多種,但它們並不等價。方法一中使用的是管道符號,這使得while語句在子shell中執行,這意味著while語句內部設定的變數、陣列、函數等在迴圈外部都不再生效。這正是文章開頭所說的陷阱。更簡單的:echo haha | a=5,在命令執行結束後,變數a的值也不再是5。其餘4種寫法,while語句都不在子shell中執行,因此都不會出現文章開頭所說的問題。

例如,使用寫法二的here string代替寫法一:

#!/bin/bash
while read line
do
    new_var=$line
done <<< "abc xyz"
echo new_var is null: $new_var?

或者使用寫法四的進程替換:

#!/bin/bash
while read line
do
    new_var=$line
done < <(echo "abc xyz")
echo new_var is null: $new_var?

由此可以說,在上面的5種寫法中,使用的最廣泛的寫法一雖然最簡單、方便,但其實是最爛的一種。

本文永久更新連結地址http://www.linuxidc.com/Linux/2017-08/146534.htm


IT145.com E-mail:sddin#qq.com