5

Is there a data structure for bash scripts that can be used similar to how something like a java.util.Set would be used? Basically a collection that even if you add a duplicate element to it won't allow you to add two of the same element?

I'm not looking to store anything complicated, just a set of strings.

Also, if it does exist, does it require a particular version of bash or is it just a POSIX compliant thing?

I'm aware that bash does have arrays, and some versions of bash have hashmaps (but not all versions).

  • Does the last sentence imply that you want it to work on all Bash versions? The answer is no in that case. – Michael Homer Apr 14 '18 at 6:39
  • @MichaelHomer Well I guess I'd like to know which versions it would work on just in case that means it will work on the version(s) I am using. – leeand00 Apr 14 '18 at 6:42
4

If all you care about is a set of strings, you can just use an associative array ("hashmap"):

declare -A hm
hm[hello]=1
hm[world]=1
hm[hello]=1
if [ "${hm[hello}" ] ; then ... ; fi

All you care about is whether there's something associated with the key or not. The value doesn't matter, we only care that there's a non-empty string there (so you can "delete" an entry by setting it to an empty string).

This would be analogous to using a HashMap<String,Object> to represent a set (which is actually what Java's HashSet does, in fact).

These associative arrays are available in Bash 4 and later, and also in zsh and ksh. They don't work in 3-series Bash versions and earlier, including macOS's Bash 3.2.


There is no POSIX equivalent. You could simulate the effect using eval if your strings are suitably restricted, or have a natural transformation to valid variable names:

hm_hello=1
hm_world=1
key=test
eval "hm_$key=1"
if [ "$(eval hm_$key)" ] ; then ... ; fi

You could also use a temporary file and grep, for example, or even lots of temporary files and the filesystem as a key store.


It's also possible (perhaps likely) that using some other tool or language is more suitable than shell script. At a minimum, awk is available on all POSIX systems and it does support string-keyed associative arrays.

If you really do have complex data-structure needs a conventional general-purpose language may be still more appropriate. Perl and Python are also widely available.

  • Unfortunately the link is dead. Does Java really create separate objects just to store a single presence bit? – Alex Jansen Mar 16 at 6:49
  • @AlexJohnson I've put in a new link. Yes, it creates an object to represent presence. The object is shared between all HashSets, so I think everyone will cope. – Michael Homer Mar 16 at 6:55
0

Things that act like a set of strings in bash:

  1. A set of newline-delimited strings processed by sort -u.

  2. The set of keys in an associative array (since version 4.0).

bash is not really a programming language with the same generality as Java, so you would have to jump through quite the number of hoops to do any sort of general programming in it, especially if you require data structures fancier than a basic array.

The arrays and associative arrays in bash are extensions to the POSIX shell standard. A POSIX shell has exactly one array ($@), and no associative arrays.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.