0

I want to be able to easily search through a list of possible asset file locations for particular files, using similar semantics to the way posix shells search for binaries along the PATH based on a command's name.

For instance, if I had this directory structure:

/usr/foo/assets
+- sounds
|  +- ding.ogg
|  +- dong.ogg
+- images
   +- foo.png

/usr/local/foo/assets
+- sounds
|  +- ding.flac      # better ding
+- images
   +- bar.png

I want to be able to define some kind of search path; for example this one, that also includes the user's own .local, then falls back to the freedesktop default sounds after my own asset folders:

FOO_SOUNDS_PATH=$HOME/.local/foo/assets/sounds:/usr/local/foo/assets/sounds:/usr/foo/assets/sounds:/usr/share/sounds/freedesktop/stereo

The end result is that I want to be able to refer to the files with only the basename, instead of manually determining the complete path myself, that would allow me to write something similar to:

#!/bin/bash

play_sound(){
  paplay $(find_on_path --ext="ogg,wav,mp3,flac" --path="$FOO_SOUNDS_PATH" "$1")
}

play_sound ding         # play /usr/local/foo/assets/sounds/ding.flac
play_sound dong         # play /usr/foo/assets/sounds/dong.ogg
# fallback to freedesktop system 'complete' sound:
play_sound complete     # play /usr/share/sounds/freedesktop/stereo/complete.ogg

Note that I'm using sound files since that's a convenient example, but I'm really interested in the more general technique, not specifically in how to play system sounds.

Is there a simple way to reuse these same $PATH semantics for other kinds of resources, and if so, how? If not, how should I be doing this instead?

1

All right, so here's one way; you may be able to wrap these ideas into a bash script or function:

$ FOO_SOUNDS_PATH=$HOME/.local/foo/assets/sounds:/usr/local/foo/assets/sounds:/usr/foo/assets/sounds:/usr/share/sounds/freedesktop/stereo
$ IFS=':' read -r -a array <<< "$FOO_SOUNDS_PATH" # IFS splits path into array var by ':'
$ echo "${array[@]}"
$ /home/sparrow/.local/foo/assets/sounds /usr/local/foo/assets/sounds /usr/foo/assets/sounds /usr/share/sounds/freedesktop/stereo

Meaning you can extrapolate:

$ for i in "${array[@]}"; do find $i -type f -name *.ogg -or -name *.wav -or -name *.mp3 -or -name *.flac -printf "%f\n"; done

Which would give you all the relevant sound files... You'd have to script the rest in order to save those files as variables to play them on command. I hope I have at least pointed you in the right direction!

1

Try some variation of this:

$ cat tst.sh
#!/bin/env bash

assPath='/foo:/bar/whatever:/somewhere/else'

assFind() {
    local tgt="$1" dir assArr
    IFS=':' read -r -a assArr <<< "$assPath"
    for dir in "${assArr[@]}"; do
        printf 'Searching "%s"\n' "$dir" >&2
        if [[ -e "${dir}/${tgt}" ]]; then
            printf '%s/%s\n' "$dir" "$tgt"
            return 0
        fi
    done
    return 1
}

assFind 'ding.ogg'

$ ./tst.sh
Searching "/foo"
Searching "/bar/whatever"
Searching "/somewhere/else"

Obviously I don't really have those directories or that file on my system, hence no stdout when i ran it.

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.