Output of previous bash loop iteration into next i

2019-08-27 20:41发布

问题:

I'm in a situation where I'm wanting to take the output of a grep command from one iteration of a for-loop and turn it into the input for the next grep command in the following iteration.

Normally, I would use an array and the for-loop to build a single grep command, however because I need the bash variable GREP_COLOR to change between iterations I'm running into this issue. I suppose I could make three different functions that all do the same thing except for that variable, but I'd prefer to have a single function if at all possible. Here's the array:

patterns=("general-red" "general-yellow" "general-green" "ha-red" "ha-yellow" "ha-green")

Here's the function:

function iterate-patterns() {
    for i in "${patterns[@]}"
    do
            if [[ "$i" = *-red ]]
            then
                    GREP_COLOR="$RED" grep -E --text --color=always --line-buffered -f /var/lib/foobar/"${i}".txt
            elif [[ "$i" = *-yellow ]]
            then
                    GREP_COLOR="$YELLOW" grep -E --text --color=always --line-buffered -f /var/lib/foobar/"${i}".txt
            elif [[ "$i" = *-green ]]
            then
                    GREP_COLOR="$GREEN" grep -E --text --color=always --line-buffered -f /var/lib/foobar/"${i}".txt 
            else
                    cat 
            fi
    done
}

Here's the function that calls that function, providing the initial input:

function daddyfunction() {

    iterate-filters |\
    iterate-experimental |\
    iterate-patterns 
}

Essentially, each item in the array represents a file for the grep -f command with many patterns to be searched for and highlighted with the desired color. However, as the code currently stands, only the first array item ends up being displayed. This I'm fairly certain is because each grep needs to be somehow changed into input for the following iteration's grep command.

Is this do-able? Am I stuck making a function for each color? Is there a better way to accomplish all this? I seek the wisdom of the internets. ;) Please and thank you.

EDIT

Just to confirm, three separate functions does work:

function iterate-redhighlights() {
    greplist=()
    for i in "${redpatterns[@]}"
    do
            if [[ "$i" = *-red ]]
            then
                    greplist+=( -f /var/lib/foobar/"${i}".txt)
            else
                    cat
            fi
    done
    GREP_COLOR="$RED" $search "${greplist[@]}"
}
function iterate-yellowhighlights() {
    greplist=()
    for i in "${yellowpatterns[@]}"
    do
            if [[ "$i" = *-yellow ]]
            then
                    greplist+=( -f /var/lib/foobar/"${i}".txt)
            else
                    cat
            fi
    done
    GREP_COLOR="$YELLOW" $search "${greplist[@]}"
}
function iterate-greenhighlights() {
    greplist=()
    for i in "${greenpatterns[@]}"
    do
            if [[ "$i" = *-green ]]
            then
                    greplist+=( -f /var/lib/foobar/"${i}".txt)
            else
                    cat
            fi
    done
    GREP_COLOR="$GREEN" $search "${greplist[@]}"
}

回答1:

You can't run grep in a loop when it's reading from stdin. The first iteration will read all of stdin, and there's no way to rewind back to the beginning for the next iteration (files support seeking, but pipes don't, and there's no shell syntax to do it).

You can copy all of stdin to a temporary file before the loop and then process that file each time. Redirect the output to another temporary file, then copy that back over the input file to prepare for the next iteration.

iterate-patterns() {
    tempfile=$(mktemp /tmp/patterns.XXXXXX)
    tempfile2=$(mktemp /tmp/patterns2.XXXXXX)
    cat > "$tempfile"
    for i in "${patterns[@]}"
    do
        if [[ "$i" = *-red ]]
        then
            GREP_COLOR="$RED" grep -E --text --color=always --line-buffered -f /var/lib/foobar/"${i}".txt "$tempfile" > "$tempfile2"
        elif [[ "$i" = *-yellow ]]
        then
            GREP_COLOR="$YELLOW" grep -E --text --color=always --line-buffered -f /var/lib/foobar/"${i}".txt "$tempfile" > "$tempfile2"
        elif [[ "$i" = *-green ]]
        then
            GREP_COLOR="$GREEN" grep -E --text --color=always --line-buffered -f /var/lib/foobar/"${i}".txt "$tempfile" > "$tempfile2"
        else
            cat "$tempfile" > "$tempfile2"
        fi
        cp "$tempfile2" "$tempfile"
    done
    cat "$tempfile"
    rm "$tempfile" "$tempfile2"
}


标签: bash grep