1

I'm trying to retrieve a value in a for loop but have failed with every effort. In this script, I have to declare the remote path for my SSHFS mount script. In the code below, I'm storing the path in an array of user[remote]. Further down in the script, this user is being held in $left. So air[remote] would be $left[remote]. I can't figure out how to do this, however. My latest effort, ${!left[remote]} didn't result in any error but just results in a null value.

How do I get the remote path value dynamically with $left[remote]?

#!/bin/bash

declare -A air
air[remote]="/home/air"

declare -A bhm
bhm[remote]="/home/bhm"

declare -A schwimserver3
schwimserver3[remote]="/var/www/clients/client1/web7/home/schwimserver3"


#echo ${air[remote]}

for u in $HOME/Remote/SSHFS/*
do
  if [ -d $u ]; then
    basename "$u" >/dev/null
    acct="$(basename -- $u)"
    
    IFS=- read -r left right <<< "$acct"
    if mountpoint "${HOME}/Remote/SSHFS/${acct}" >/dev/null; then
        printf '%b\n' "unmount ${right},fusermount -u /home/schwim/Remote/SSHFS/${right}"
    else
        printf '%b\n' "mount ${right},sshfs -o workaround=rename $left@$right:${!left[remote]} /home/schwim/Remote/SSHFS/${acct}"
    fi

  fi
done

thanks for your time!

3

2 Answers 2

1

The issue is, you need to double interpret the array. If left="air", the $left[remote] does NOT equal air[remote].
To perform the double substitution, you need to first interret the $left into air, then interpret air[remote] Like this:
$ air[remote]="/home/air" $ left="air" ; For clarity, lets make a temporary variable with the first substitution $ name_var='${'$left'[remote]}' ; Lets see the value of name_var $ echo $name_var ${air[remote]} ; Now, we need to force the shell to interpret this value $ eval echo $name_var /home/air ; Or, to store this in a value resolved_value=$( eval echo $name_var )
Or, as a one liner:
resolved_value=$( eval echo '${'$left'[remote]}' )

How this works:
The trick is in the creation of the $name_var:
'${' (with single quotes, not double) says use the characters as is (i.e. not interpret them as a variable named {
$left will then be substituted with it's value "air"
'[remote]}' will use these characters as is. (Again, single quotes, not double)
the eval command then substitutes the characters (or contents of the variable $name_var) into the interpreter and processes its results, which is then the value of the variable ${air[remote]}"

In your code, you can either build the $resolved_value variable and put in into your script:
printf '%b\n' "mount ${right},sshfs -o workaround=rename $left@$right:${resolved_value} /home/schwim/Remote/SSHFS/${acct}"

Or insert the entire expression:
printf '%b\n' "mount ${right},sshfs -o workaround=rename $left@$right:$( eval echo '${'$left'[remote]}' ) /home/schwim/Remote/SSHFS/${acct}"

Although the first option is better for readability.

0

Why don't you invert the array:

declare -A remotes=(
    [air]="/home/air"
    [bhm]="/home/bhm"
    [imserver3]="/var/www/clients/client1/web7/home/schwimserver3"
)

Then you'd use "${remotes[$left]}".

This is why associative arrays are so useful: you don't have to use dynamic variable names.


To use dynamic names, use bash version 4.3+ and use namerefs:

declare -A foo=( [bar]=baz )
left=foo
declare -n ref=$left
echo "${ref[bar]}"

Refer to. 3.4 Shell Parameters in the manual

1
  • Thank you so much for the help! The reason I was trying to do it that way was that I was hoping to place more into the array, for instance if I were able to figure it out, I was going to move user, remote, local info into it. Commented Nov 24, 2020 at 20:02

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .