Bash多进程和访问网络

November 7, 2013

真心不想用Bash做这事。

获得HTTP状态

这么简单的功能,还是比新开一个curl要慢。

function get_http_status() {
    # 去掉http://
    local url=${1#http://}

    # 获得端口
    local port=80
    if [[ $url =~ :([0-9]+) ]]; then
	port=${BASH_REMATCH[1]}
    fi

    # 获得主机
    if [[ $url =~ ([^:/]*) ]]; then
	host=${BASH_REMATCH[1]}
    fi

    # 获得路径
    local query=${url#*/}
    if [[ $host = $query || $host:$port = $query ]]; then
	query=""
    fi

    # 连接
    exec 3<>/dev/tcp/$host/$port
    #发HEAD请求
    echo -e "HEAD /$query HTTP/1.1\r\nConnection: close\r\n\r\n" >&3
    # 读状态
    read status <&3
    echo $1:${status:9:3}
}

顺便练了练正则表达式,好麻烦。

coproc多进程

只是把文件分割然后用多个进程处理,最后合并。

# 处理一个文件
loop_file() {
    local input_file=$1
    local output_file=$2

    mapfile urls < $input_file
    for url in ${urls[@]} ; do
            get_http_status $url >> $output_file
    done
}

# 用coproc在子shell异步处理各个文件
for f in input_file*; do
    # 因为coproc不把第一个参数做变量展开,只好用eval展开,再传给coproc
    eval "coproc $f { loop_file $f output-$f; }"
done

# 用wait等待全部的子shell完成
for f in $input_file*; do
    pid=$f_PID
    wait ${!pid}
done

# 合并结果,删除中间文件
for f in $ input_file* ; do
    cat output-$f >> output.txt && rm output-$f
done

考虑过用管道实现生产者/消费者模式,实在太复杂,最后换成文件分割。