在bash中使用子进程外的变量

时间:2014-10-17 18:48:04

标签: bash function shell

getStrings()函数调用getPage()函数返回一些html页面。该html通过egrepsed组合传输,仅获得3个字符串。然后我尝试使用link构造将每个字符串分别放入单独的变量profilegallerywhile read..。但它只能在while...done循环内部工作,因为它在子进程中运行。如何在getStrings()函数之外使用这些变量?

getStrings() {
    local i=2
    local C=0
    getPage $(getPageLink 1 $i) |
    egrep *some expression that results in 3 strings* | 
        while read line; do
            if (( (C % 3) == 0 )); then 
                link=$line
            elif (( (C % 3) == 1 )); then
                profile=$line
            else
                gallery=$line
            fi
            C=$((C+1)) #Counter
        done
}

2 个答案:

答案 0 :(得分:4)

简单:不要在子流程中运行循环:)

要实际完成,您可以使用流程替换。

while read line; do
    ...
done < <(getPage $(getPageLink 1 $i) | egrep ...)

对于好奇的,POSIX兼容的方法是使用命名管道(可能bash使用命名管道来实现进程替换):

mkfifo pipe
getPage $(getPageLink 1 $i) | egrep ... > pipe &
while read line; do
    ...
done < pipe

bash 4.2开始,您可以设置lastpipe选项,这会导致管道中的最后一个命令在当前shell中运行,而不是子shell。

shopt -s lastpipe
getPage $(getPageLink 1 $i) | egrep ... | while read line; do
   ...
done

但是,使用while循环不是设置三个变量的最佳方法。在命令组中调用read三次更容易,因此它们都从同一个流中读取。在上述三种情况中的任何一种情况下,用

替换while循环
{ read link; read profile; read gallery; }

如果您想要更灵活一点,请将您可能想要读取的变量的名称放在数组中:

fields=( link profile gallery )

然后用这个for循环替换while循环:

for var in "${fields[@]}"; do read $var; done

通过编辑fields数组以获得适当的字段名称,这可以让您轻松调整代码,如果管道返回更多或更少的行。

答案 1 :(得分:0)

使用数组再解决一次:

getStrings() {
array_3=( `getPage | #some function
    egrep | ...` ) #pipe conveyor
}