1

I'm making a .bashrc function to get me around the system faster. I used a case statement to state where I want to go.

function da() {
case "$1" in 
    home)   cd ~
            ;;
    eolas) cd /home/eolas/
           ;;
esac
}

I want to import the cases from a JSON file, example:

{
  "cases": {
    "home": "~",
    "eolas": "/home/eolas/",
    "jdan": "/home/jdan/",
    "kl": "/.kl/"
  }
}

I have search for a way to do this but so far haven't found one, is this possible in bash? And if so how?

4
  • Have you looked into jq or do you desire a pure bash solution?
    – Hermann
    Mar 26 '20 at 22:01
  • will do look into it
    – jDan
    Mar 26 '20 at 22:16
  • Are you aware you can write cd ~eolas ? Mar 27 '20 at 12:53
  • How strict are you with the format of the JSON file? Could the list, for example, be turned into an array rather than a series of objects, as in {"cases":[["home","~"],["eolas","/home/eolas/"],["jdan","/home/jdan/"],["kl","/.kl/"]]}?
    – Kusalananda
    Apr 12 '20 at 15:26
0

If you have a JSON file, automatically you should think about using to parse it.

You'll want to read that file into an associative array:

declare -A __dirmap
while IFS=$'\t' read -r name dir; do
    [[ $dir == "~" ]] && __dirmap[$name]=$HOME || __dirmap[$name]=$dir
done < <(
    jq -r '.cases | to_entries[] | [.key, .value] | @tsv' file.json
)

Then the function can be

function da() {
    if [[ -v __dirmap[$1] ]]; then
        cd "${__dirmap[$1]}"
    else
        echo "No mapping for $1" >&2
    fi
}
2
  • I find jq hard to write, someone can help tighten that up. Mar 27 '20 at 12:51
  • The jq expression looks fine for what you're using it for. A small caveat is that some esoteric labels and directory paths may end up encoded (like those containing newlines or tabs).
    – Kusalananda
    Aug 7 at 10:12
0

I'm going to use your JSON to build a associative array of case labels and their corresponding directories. This could be done once in your ~/.bashrc file:

unset _da_map
declare -A _da_map

if [ -f da_map.json ]; then
    eval "$(
            jq -r '.cases | to_entries[] |
                   @sh "_da_map[\(.key)]=\(.value)"' da_map.json
    )"
fi

(Or put it in a separate da_init function so that you can call it whenever you change the da_map.json file.)

The jq statement build a number of variable assignment that the eval evaluates. The @sh operator quotes the relevant strings for the shell. For the given example, this would result in the following code being run:

_da_map['home']='~'
_da_map['eolas']='/home/eolas/'
_da_map['jdan']='/home/jdan/'
_da_map['kl']='/.kl/'

The da function could then be written like

da () {
        command cd -- "${_da_map["$1"]?No mapping for label "'$1'"}"
}

This uses the associative array that was previous created to cd to the directory associated with the given argument. If no mapping is found for the given argument, the expansion generates an error:

$ da "hello world"
bash: _da_map["$1"]: No mapping for label 'hello world'

One issue with this naive approach is that it does not allow for tilde expansion (or variable expansions for that matter) in the values of the directories in the JSON file. You therefore should write paths without the use of ~ and without variables.

-2

Not exactly elegant, but seems to work:

in='
{
  "cases": {
    "home": "~",
    "eolas": "/home/eolas/",
    "jdan": "/home/jdan/",
    "kl": "/.kl/"
  }
}
'

case="$(echo "$in" |
          perl -pe 's/"cases". \{/case "\$1" in/;
                    s/: /) eval cd /;
                    s/,/;;/;
                    s/[{}]//g')"

eval "
  function da() {
      $case
    esac
  }
"
1
  • Thank you for the quick response!
    – jDan
    Mar 26 '20 at 22:23

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.