Home > Back-end >  How to iterate over multiple variables and echo them using Shell Script?
How to iterate over multiple variables and echo them using Shell Script?

Time:10-08

Consider the below variables which are dynamic and might change each time. Sometimes there might even be 5 variables, But the length of all the variables will be the same every time.

var1='a b c d e... upto z'
var2='1 2 3 4 5... upto 26'
var3='I II III IV V... upto XXVI'

I am looking for a generalized approach to iterate the variables in a for loop & My desired output should be like below.

a,1,I
b,2,II
c,3,III
d,4,IV
e,5,V
.
.
goes on upto
z,26,XXVI

If I use nested loops, then I get all possible combinations which is not the expected outcome.

Also, I know how to make this work for 2 variables using for loop and shift using below link https://unix.stackexchange.com/questions/390283/how-to-iterate-two-variables-in-a-sh-script

CodePudding user response:

With paste

paste -d , <(tr ' ' '\n' <<<"$var1") <(tr ' ' '\n' <<<"$var2") <(tr ' ' '\n' <<<"$var3")
a,1,I
b,2,II
c,3,III
d,4,IV
e...z,5...26,V...XXVI

But clearly having to add other parameter substitutions for more varN's is not scalable.

CodePudding user response:

You need to "zip" two variables at a time.

var1='a b c d e...z'
var2='1 2 3 4 5...26'
var3='I II III IV V...XXVI'

zip_var1_var2 () {
    set $var1
    for v2 in $var2; do
        echo "$1,$v2"
        shift
    done
}

zip_var12_var3 () {
    set $(zip_var1_var2)
    for v3 in $var3; do
        echo "$1,$v3"
        shift
    done
}

for x in $(zip_var12_var3); do
  echo "$x"
done

If you are willing to use eval and are sure it is safe to do so, you can write a single function like

zip () {
    if [ $# -eq 1 ]; then
        eval echo \$$1
        return
    fi

    a1=$1
    shift
    x=$*

    set $(eval echo \$$a1)
    for v in $(zip $x); do
        printf '=== %s\n' "$1,$v" >&2
        echo "$1,$v"
        shift
    done
}

zip var1 var2 var3  # Note the arguments are the *names* of the variables to zip

If you can use arrays, then (for example, in bash)

var1=(a b c d e)
var2=(1 2 3 4 5)
var3=(I II III IV V)

for i in "${!var1[@]}"; do
    printf '%s,%s,%s\n' "${var1[i]}" "${var2[i]}" "${var3[i]}"
done

CodePudding user response:

Use this Perl one-liner:

perl -le '@in = map { [split] } @ARGV; for $i ( 0..$#{ $in[0] } ) { print join ",", map { $in[$_][$i] } 0..$#in; }' "$var1" "$var2" "$var3"

Prints:

a,1,I
b,2,II
c,3,III
d,4,IV
e,5,V
z,26,XXVI

The Perl one-liner uses these command line flags:
-e : Tells Perl to look for code in-line, instead of in a file.
-l : Strip the input line separator ("\n" on *NIX by default) before executing the code in-line, and append it when printing.

The input variables must be quoted with double quotes "like so", to keep the blank-separated words from being treated as separate arguments.
@ARGV is an array of the command line arguments, here $var1, $var2, $var3.
@in is an array of 3 elements, each element being a reference to an array obtained as a result of splitting the corresponding element of @ARGV on whitespace. Note that split splits the string on whitespace by default, but you can specify a different delimiter, it accepts regexes.
The subsequent for loop prints @in elements separated by comma.

SEE ALSO:
perldoc perlrun: how to execute the Perl interpreter: command line switches
perldoc perlvar: Perl predefined variables

  • Related