1

I already know how to generate pairs by taking one variable from each of a set of arrays, as such:

#!/bin/bash
dir1=(foo baz)  # Not ideal: Want inputs to be dir1=(foo bar); dir2=(baz bat) instead
dir2=(bar bat)
for i in "${!dir1[@]}"
do
  echo "Comparing ${dir1[i]} to ${dir2[i]}"
done

Produces the following output.

Comparing foo to bar
Comparing baz to bat


Is there a way to do this loop with foo bar on the same line and baz bat on it's same line? As follows.

pair1=(foo bar)
pair2=(baz bat)
...
pairN=(qux quux)
...
do
  # then, inside the loop, compare the pair
done
Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
Let Me Tink About It
  • 15,156
  • 21
  • 98
  • 207
  • 3
    Possible duplicate of [bash How to declare and iterate over pairs of values where values may contain spaces (two dimensional array)](https://stackoverflow.com/questions/32871443/bash-how-to-declare-and-iterate-over-pairs-of-values-where-values-may-contain-sp) – Ipor Sircer Dec 11 '18 at 22:32
  • You could use `echo -n ...` – Red Cricket Dec 11 '18 at 22:34
  • 1
    Do you want to loop over the `pairX` arrays, and for each array compare the first and second element? – Benjamin W. Dec 11 '18 at 22:40

1 Answers1

3

You can use ${!prefix@} to iterate over variable names starting with prefix, and namerefs to refer to content stored under each name:

#!/usr/bin/env bash
case $BASH_VERSION in ''|[123].*|4.[012].*) echo "ERROR: Bash 4.3 required" >&2; exit 1;; esac

pair1=(foo bar)
pair2=(baz bat)
pairN=(qux quux)

declare -n currPair
for currPair in "${!pair@}"; do
  echo "Comparing ${currPair[0]} to ${currPair[1]}"
done

See this running at https://ideone.com/pTehPZ

Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
  • If you move the `declare -n` statement outside of the loop with `declare -n arrayName`, the nameref will be established for each value of `"${!pair@}"`, and you don't need to introduce a separate variable. – Benjamin W. Dec 11 '18 at 22:45
  • I'm not sure I like that syntax -- it feels magical (in terms of not having a good way to disambiguate whether the nameref is being retargeted, or its target's value is being updated). – Charles Duffy Dec 11 '18 at 22:47
  • Fair enough. I discovered the option only after always doing it like you show, and I prefer it for brevity. – Benjamin W. Dec 11 '18 at 22:49
  • Following my own link, though, I *do* see that it's documented (at least on the bash-hackers' wiki), so... – Charles Duffy Dec 11 '18 at 22:52
  • 1
    Also in the manual, [here](https://www.gnu.org/software/bash/manual/bash.html#Shell-Parameters): "If the control variable in a `for` loop has the nameref attribute, the list of words can be a list of shell variables, and a name reference will be established for each word in the list, in turn, when the loop is executed." – Benjamin W. Dec 11 '18 at 22:54