-2

I have an requirement wherein I have multiple values in a file and 8 arrays containing numeric values. For example:

Array1=(1 2 3 4 5) 
Array2=(6 7 8 9 10) 

File has values 3 and 9. So it should return Array1 in first case and Array2 in second case. Also I want to store the result in another file having value followed by array name that contains that value.

Unable to find any solution.

Cyrus
  • 84,225
  • 14
  • 89
  • 153
  • 1
    Can you redefine your question? Problem description and statement seems confusing. – Vraj Bhatt Jul 28 '23 at 05:52
  • 2
    Please add a desired output and also what have you tried so far. – Jetchisel Jul 28 '23 at 06:13
  • This sounds a little complex for bash. You need something to associate a name with an array, such as a tuple or a class, or a map/dict or multidimensional array, and I don't think bash supports any of those. You can really twist the parameter expansion syntax (`${...}`) to emulate them, but that is undecipherable torture. Awk might be powerful enough, but if not Python, Perl, and many other languages definitely would work. – John Bayko Jul 28 '23 at 06:14
  • @JohnBayko _You need something to associate a name with an array_: Recent `bash` supports namerefs. And `grep` suffices for the rest (see my answer). – Renaud Pacalet Jul 28 '23 at 08:29
  • 1
    Hi @VrajBhatt, Thanks for replying back. I'll be short and precise. I have 2 arrays (listed in question) and a separate text file having numeric values in it say 3 9. I want to search these values (3 9) in those arrays and return the array name which has those values present in it. The output file should contain 2 lines in it. 1st line (3 Array1) 2nd line (9 Array2) i.e value and the array name in which it is present. – Nitin Kumar Jul 28 '23 at 10:52
  • Hi @Jetchisel, Thanks for replying back. But am blocked. Don't know how to start with the solution. Its just that I have declared arrays :) New to stackoverflow so unsure about proper formatting but the desired output can be found in my above comment. Bash should be able to create an output file having 2 lines in it. 1st line (3 Array1) 2nd line (9 Array2) i.e value and the array name in which it is present. – Nitin Kumar Jul 28 '23 at 11:15

2 Answers2

2

If your bash is recent enough:

for a in Array1 Array2; do
  declare -n arr="$a"
  grep -oFf <(printf '%s\n' "${arr[@]}") file && printf '(in %s)\n' "$a"
done > results

Explanation:

  • declare -n arr="$a" declares a nameref, a kind of alias. If executed when the value of a is Array1, arr becomes a synonym of Array1.
  • printf '%s\n' "${arr[@]}" prints each entry in array arr on a separate line.
  • <(command) is a process substitution, the command is run and its output is seen as a file by the environment. In our case the content of the array is considered as a file with one entry per line.
  • grep -oFf file1 file2 takes the patterns to search in file1 (-f file1), in our case in the process substitution, considers them as plain text strings, not regular expressions (-F), and outputs only the matched parts (-o).
  • grep exits with status 0 if a pattern matched, else it exits with a non-zero status. As the 0 exit status is considered as boolean true, the printf '(in %s)\n' that prints the array name is executed only if grep found one of the patterns in file, thanks to the && operator (AND).

Demo (output prefixed with -| ):

printf '3\n9\n15\n' > file
Array1=(1 2 3 4 5)
Array2=(6 7 8 9 10)
Array3=(a b c d e)
for a in Array1 Array2 Array3; do
  declare -n arr="$a"
  grep -oFf <(printf '%s\n' "${arr[@]}") file && printf '(in %s)\n' "$a"
done > results
cat results
-| 3
-| 1
-| 5
-| (in Array1)
-| 9
-| (in Array2)
Renaud Pacalet
  • 25,260
  • 3
  • 34
  • 51
0

Try this Shellcheck-clean pure Bash code:

#! /bin/bash -p

Array1=(1 2 3 4 5) 
Array2=(6 7 8 9 10) 

while read -r val || [[ -n $val ]]; do
    for arr in Array1 Array2; do
        aref="${arr}[@]"
        for elem in "${!aref}"; do
            if [[ $elem == "$val" ]]; then
                printf '%s %s\n' "$val" "$arr"
                break
            fi
        done
    done
done <file
pjh
  • 6,388
  • 2
  • 16
  • 17
  • Hi PJH, Thanks for replying .. will it work in case of shell. My script starts with #!/bin/sh. Also I have 4.4.20 version Bash installed in my server. – Nitin Kumar Jul 28 '23 at 11:11
  • @NitinKumar, it will work if `/bin/sh` is really Bash. If `/bin/sh` is `dash` then nothing will work because `dash` does not support arrays. If your code depends on Bash-specific features, including arrays, it should start with `#! ...bash...`. Run [Shellcheck](https://www.shellcheck.net/) on your code to find features that are not guaranteed to be supported by `/bin/sh` (and many other common problems with shell code). The code in the answer should work with *any* version of Bash since 3.0. I tested it on 3.2 and 5.2. – pjh Jul 28 '23 at 11:31
  • @NitinKumar, see [Difference between sh and Bash](https://stackoverflow.com/q/5725296/4154375). – pjh Jul 28 '23 at 11:33
  • Hi pjh, Thanks for the help, It works – Nitin Kumar Jul 31 '23 at 14:00