coproc和子流程重定向的替代方案(Bash 3)

时间:2014-01-26 18:34:53

标签: bash shell coproc

好的,所以我的情况是我真的想要通过coproc或通过重定向(例如<(some command))使用协同进程,但不幸的是我只限于bash 3.2在我的一个目标环境中,这意味着我的能力有限。

我需要协同处理的原因是我需要从一个文件逐行读取,同时循环到另一个文件。

目前我正在使用exec <6 /foo/bar创建一个文件打开供阅读,以便每当我需要更多输入时我都可以read line <&6。这样可以正常工作,但它只适用于纯文本文件,但实际上我想保持我的文件压缩,而不是在运行我的脚本之前解压缩它们。

我还需要能够写一个新的压缩文件,而不必浪费空格写入纯文本,然后压缩。

那么...... bash 3中有没有其他选择?正如我已经注意到的那样,我已经在另一个文件的循环中,所以我没有选择将输出汇总到gzip(或管道zcat到我的循环中),因为我我需要独立于我的循环。

试图举一个例子,这是我现在正在做的一个精简版:

# Decompress compressed match-file
gzip -dc /foo/compressed.gz > /tmp/match

# Setup file handles (to keep files open for reading/writing)
exec 5< /tmp/match
exec 6> /tmp/matches

# Loop over input file (/foo/bar) for matches
read next_match <&5
while read line; do
    if [ "$line" = "$next_match" ]; then
        read next_match <&5
        echo "$line" >&6
    fi

    echo "$line"
done < /foo/bar

# Close file handles
exec <5&-
exec 6>&-
rm /tmp/match

# Compress matches and overwrite old match file
gzip -cf9 /tmp/matches /foo/compressed.gz
rm /tmp/matches

原谅任何拼写错误,以及实际脚本的一般无用,我只是想让它保持相当简单。正如您所看到的,虽然它工作正常,但由于浪费的纯文本文件,它并不是最佳的。

2 个答案:

答案 0 :(得分:3)

您可能希望使用mknod创建管道并让gzip在后​​台进程中进行写入/读取。以下似乎对我有用:

#!/bin/bash

# create test files (one character per line)
echo abcdefgh | grep -o . | gzip > /tmp/foo.gz
echo aafbchddjjklsefksi | grep -o . > /tmp/bar

# create pipes for zipping an unzipping
PIPE_GUNZIP=/tmp/$$.gunzip
PIPE_GZIP=/tmp/$$.gzip
mkfifo "$PIPE_GUNZIP"
mkfifo "$PIPE_GZIP"

# use pipes as endpoints for gzip / gunzip
gzip -dc /tmp/foo.gz > "$PIPE_GUNZIP" &
GUNZIP_PID=$!
gzip -c9 > /tmp/foo.gz.INCOMPLETE < "$PIPE_GZIP" &
GZIP_PID=$!

exec 5< "$PIPE_GUNZIP"
exec 6> "$PIPE_GZIP"

read next_match <&5
while read line; do
    if [ "$line" = "$next_match" ]; then
        read next_match <&5
        echo "$line" >&6
    fi

    echo "$line"
done < /tmp/bar

# Close file handles
exec 5<&-
exec 6>&-

# wait for gzip to terminate, replace input with output, clean up
wait $GZIP_PID
mv /tmp/foo.gz.INCOMPLETE /tmp/foo.gz
rm "$PIPE_GZIP"

# wait for gunzip to terminate, clean up
wait $GUNZIP_PID
rm "$PIPE_GUNZIP"

# check result
ls -l /tmp/{foo,bar}*
gzip -dc /tmp/foo.gz

答案 1 :(得分:1)

由于bash 3.2中提供了流程替换,您只需使用它即可。

# Setup file handles (to keep files open for reading/writing)
exec 5< <( gzip -dc /foo/compressed.gz )
exec 6> >( gzip -c9 /foo/new_compressed.gz)

# Loop over input file (/foo/bar) for matches
read next_match <&5
while read line; do
    if [ "$line" = "$next_match" ]; then
        read next_match <&5
        echo "$line" >&6
    fi

    echo "$line"
done < /foo/bar

# Close file handles
exec <5&- 6>&-

# Overwrite old match file
mv /foo/new_compressed.gz /foo/compressed.gz