How can I get mount_smbfs
to work on a Mac zsh terminal from within a loop?
The identical commands work when run one by one, but they throw an error when issued from within a loop: no such file or directory: mount_smbfs {mount point} {local directory}
.
So, when I source something like this (the export commands actually live in their own script that gets sourced first):
export H_DIR="/mnt/${USER}"
export I_DIR="/mnt/I"
export DUM_HOST="dummy.host.ninja"
declare -A mounts
mounts[${H_DIR}]="//${USER}@${DUM_HOST}/${USER}"
mounts[${I_DIR}]="//${DUM_HOST}/I"
for dir mount_point in ${(kv)mounts}; do
if [ ! -d $dir ]; then
echo "Making $dir and intermediates."
mkdir -p $dir
#else
#command="diskutil unmount $dir"
#echo "command: $command"
#$command
fi
command="mount_smbfs $mount_point $dir"
echo "command: $command"
$command
ls -alt $dir
done
I get something like this:
command: mount_smbfs //me@dummy.host.ninja/me /mnt/me
/Users/me/.zsh_setup/mount_all.zsh:24: no such file or directory: mount_smbfs ///me@dummy.host.ninja/me /mnt/me
total 0
drwxr-xr-x 3 me staff 96 Dec 20 14:30 ..
drwxr-xr-x 2 me staff 64 Dec 20 14:30 .
command: mount_smbfs //dummy.host.ninja/I /mnt/I
/Users/me/.zsh_setup/mount_all.zsh:24: no such file or directory: mount_smbfs ///dummy.host.ninja/I /mnt/I
total 0
drwxr-xr-x 3 me staff 96 Dec 20 14:30 ..
drwxr-xr-x 2 me staff 64 Dec 20 14:30 .
But, I can just paste the same command that was run in the loop, and it works.
me@my_mac ~ % mount_smbfs //me@dummy.host.ninja/me /mnt/me
Password for dummy.host.ninja:
me@my_mac ~ %
me@my_mac ~ % ls -alt /mnt/me
total 1499808
drwxr-xr-x 3 me staff 96 Dec 20 14:30 ..
drwx------ 1 me staff 16384 Dec 20 14:02 .
-rwx------ 1 me staff 10621 Dec 20 14:02 .bash_history
... A bunch more folders that live on the mounted host ...
me@my_mac ~ %
me@my_mac ~ %
me@my_mac ~ % mount_smbfs //dummy.host.ninja/I /mnt/I
me@my_mac ~ %
me@my_mac ~ % ls -alt /mnt/I
total 960
drwx------ 1 me staff 16384 Dec 20 18:33 .snapshot
drwxr-xr-x 7 me staff 224 Dec 20 14:30 ..
drwx------ 1 me staff 16384 Sep 21 11:22 .
... A bunch more folders that live on the mounted host ...
me@my_mac~ %
For context:
me@my_mac ~ % ls -l /
total 9
drwxrwxr-x 21 root admin 672 Dec 17 11:03 Applications
drwxr-xr-x 67 root wheel 2144 Dec 16 10:03 Library
drwxr-xr-x@ 9 root wheel 288 Oct 12 23:06 System
drwxr-xr-x 6 root admin 192 Dec 16 09:45 Users
drwxr-xr-x 3 root wheel 96 Dec 20 12:38 Volumes
drwxr-xr-x@ 38 root wheel 1216 Oct 12 23:06 bin
drwxr-xr-x 2 root wheel 64 Oct 12 23:06 cores
dr-xr-xr-x 3 root wheel 4507 Dec 20 12:38 dev
lrwxr-xr-x@ 1 root wheel 11 Oct 12 23:06 etc -> private/etc
lrwxr-xr-x 1 root wheel 25 Dec 20 12:38 home -> /System/Volumes/Data/home
lrwxr-xr-x 1 root wheel 26 Dec 20 12:38 mnt -> Users/me/mounts
... and so on ...
me@my_mac ~ %
me@my_mac ~ % ls -l /Users/me/mounts
total 32
drwx------ 1 me staff 16384 Sep 21 11:22 I
drwxr-xr-x 3 me staff 96 Dec 20 14:30 me
me@my_mac ~ %
I need to enter my password once for the first mount, but not again because I use ssh keys. If I mount one manually to open the ssh key then run the for loop with other locations, that still won't work, so I don't think that's the issue.
As @GordonDavisson mentioned in the comments, the issue isn't with mount_smbfs
but with how the command is parsed when assigned to a string variable. The best solution is to not do this, as seen here: Assigning command to a variable in Zsh. There are some suggestions for how to use a string variable as your actual command call, but I opted for just not doing it.
Making this minimum change works:
command="mount_smbfs $mount_point $dir"
echo "command: $command"
# Replace ...
# $command
# ... with the actual command:
mount_smbfs $mount_point $dir
Assigning the full command to a string was just for the convenience of echoing the command to the console before calling it, for logging and debugging. You can still do this, but it just won't be so tightly associated with the command itself, which isn't a real problem in this context where the command string variable is only used once right before calling the actual command. There are some suggestions in the linked post for how to get around this if you really want to use a string variable as your actual command call.
Also as mentioned in the comments and the linked post, it is perhaps best to wrap the command in a function. I tend to disagree in cases like this where it is a one-line command that is essentially function call itself. I'm not doing anything but calling it, no extra validation or anything. Wrapping it just adds an unnecessary layer of convolution. However, I haven't sought out a full explanation for why it might still be best practice.
That said, I will re-wrap the full script (minus the exports) back up into a set of functions as I originally did before troubleshooting and posting here. That's a good case for a function encapsulating a command or set of commands.