2

I want to join an array of strings on the string "%2C+". My shell script launch looks like this.

#!/bin/bash

function join_by { local d=$1; shift; echo -n "$1"; shift; printf "%s" "${@/#/$d}"; }

selectQuery=$(join_by "%2C+" $1)
echo selectQuery

But when I run ./download-data $("state_code" "county_code"), I get this error in the terminal: bash: state_code: command not found.

I need to pass the argument as an array since I plan to pass more arrays later on. Something like ./download-data $("state_code" "county_code") $("more" "string").

Username
  • 3,463
  • 11
  • 68
  • 111
  • 2
    There is no such thing as an array literal in `bash`; `x=(a b)` is a special form of the assignment statement. `$(...)` is a command substitution. – chepner Apr 26 '18 at 04:51
  • 3
    There are also no array values in shell. A name with the array attribute set allows syntax that *simulates* some aspects of a traditional array, but any expansion still only produces one or more distinct words, not a first-class value that contains all the array elements. – chepner Apr 26 '18 at 04:53
  • @Username : Since arrays are not "first class citizens" in bash, you can't pass them to a bash function. You could pass the *name* of a variable holding an array to the function, and then use, for instance, `eval`, but this is ugly. For me, this would be the point where I would think of replacing bash by a programming language which is better suitable for your application. – user1934428 Apr 26 '18 at 08:42

1 Answers1

2

Make your script accept multiple strings in separate arguments:

#!/bin/bash

function join_by { local d=$1; shift; echo -n "$1"; shift; printf "%s" "${@/#/$d}"; }

selectQuery=$(join_by "%2C+" "$@")
echo "$selectQuery"

and then run it with multiple arguments:

./download-data "state_code" "county_code"
that other guy
  • 116,971
  • 11
  • 170
  • 194
  • Sorry, I should clarify: I need to pass an array since I plan to pass multiple arrays in the future as I modify this script. – Username Apr 26 '18 at 01:24
  • 3
    You can't: arguments are always a single list of strings. Do like `find`, `parallel` and others and designate a certain word as your separator. Then run e.g. `./download-data array1 array1 -- array2 array2`. Alternatively, do like gcc and run `./download-data "array1 array1" "array2 array2"` and split the strings yourself – that other guy Apr 26 '18 at 02:48
  • 1
    Or give the length of each array followed by its elements. You'd run it like `./download-data "${#array1[@]}" "${array1[@]}" "${#array2[@]}" "${array2[@]}"`, and if array1 had two elements and array2 had four, it'd be like running `./download-data 2 array1elem0 array1elem1 4 array2elem0 array2elem1 array2elem2 array2elem3`. – Gordon Davisson Apr 26 '18 at 05:29
  • @GordonDavisson Would I need to change my script? If so, how? – Username Apr 26 '18 at 06:14
  • 1
    @Username Probably, but how you need to change it depends on what you're actually trying to do. What does it do differently with multiple arrays vs a single array? – Gordon Davisson Apr 26 '18 at 06:34
  • @GordonDavisson I'd assign the other arrays to different variables – Username Apr 26 '18 at 06:37
  • 1
    @Username But what would you do with them? If you're just going to append them together, then it doesn't matter where one ends and the next begins. If you're doing something else... it'll depend on what that something else is. – Gordon Davisson Apr 26 '18 at 07:07
  • I'd like to take each array, join them by a string, then use each string as the value in parameters of a URL. – Username Apr 26 '18 at 07:12