Thursday, November 18, 2021

[SOLVED] Why variable changed after pipe?

Issue

The related stub is like:

tag=('*' '#')
i=0
function output()
{
    ifs="$IFS"
    IFS=$'\n'
    for line in $@
    do
        echo $'\t' "${tag[$i]}" $line
    done
    IFS="$ifs"
    echo $i
    i=$((i+1))
    echo $i
    i=$((i%2))
    echo $i
}

output a|tee README
output b

What I want to do is:

Every time execute output to output a message block, different prefix(${tag[$ind]}) can be used for distinguishing itself from context. Besides, part-message can be redirect to file.

Result of it is:

         * a
    0
    1
    1
         * b
    0
    1
    1

With the pipe |tee README, variable $i had been reset to 0.

Why it happened and can I implement the function by this train of thought?

Thanks.


Solution

It happens becase, as stated at Bash manual, each command in a pipeline is executed as a separate process (i.e., in a subshell).

In order to preserve i variable value I suggest you to enclose the two output calls into a single shell process as follow:

#!/bin/bash

tag=('*' '#')

i=0

function output()
{
    ifs="$IFS"
    IFS=$'\n'
    for line in $@
    do
        echo $'\t' "${tag[$i]}" $line
    done
    IFS="$ifs"
    echo $i
    i=$((i+1))
    echo $i
    i=$((i%2))
    echo $i
}

(
    output a
    output b
) | tee README


Answered By - Antonio Petricca