3

TLDR for those who googled and found this

In Catalina, launchd can't read files or run scripts located inside your ~/Documents folder. Just avoid putting your scripts there and rewrite your scripts not to read files in ~/Documents. Creating a new file or symlink will work, though. See the answer below for details.


Original question

I came via this answer to help me create a script that will update a symlink every day.

And there was an article it links to teaching me how to use plist and launchctl

SO this is my plist com.journal.today.plist which is installed in ~/Library/LaunchAgents

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>

    <key>Label</key>
    <string>com.journal.today.plist</string>

    <key>RunAtLoad</key>
    <true/>

    <key>StandardErrorPath</key>
    <string>/Users/kim/journals/stderr.log</string>

    <key>StandardOutPath</key>
    <string>/Users/kim/journals/stdout.log</string>

    <key>EnvironmentVariables</key>
    <dict>
      <key>PATH</key>
      <string><![CDATA[/usr/local/bin:/usr/local/sbin:/usr/bin:/bin:/usr/sbin:/sbin]]></string>
    </dict>

    <key>WorkingDirectory</key>
    <string>/Users/kim/journals</string>

    <key>ProgramArguments</key>
    <array>
      <string>./makeTodaySym.sh</string>
    </array>

  </dict>
</plist>

When i check the stderr I saw the below

shell-init: error retrieving current directory: getcwd: cannot access parent
  1 bash: ./makeTodaySym.sh: Operation not permitted

stdout.log was empty

How do I solve this?


My original script

#!/usr/bin/env bash

date=`date +"%Y-%m-%d %A"`
folder="." # replace with full path to desired folder
file="$folder/$date.md"

if [ ! -f "$file" ]; then
    touch "$file"
    echo "Created file: $file"
fi

ln -sf "$file" "$folder/today.md"
echo "Created link to file: $file"

After trying out jksoegaard answer, the last part of my plist looks like this:

<key>ProgramArguments</key>
<array>
  <string>/Users/kim/journals/makeTodaySym.sh</string>
</array>

Latest change after taking jaume comment

<key>ProgramArguments</key>
<array>
  <string>/bin/bash</string>
  <string>/Users/kim/journals/makeTodaySym.sh</string>
</array>

Latest change

in the bash script

folder="$1" # replace with full path to desired folder

in the plist

<key>ProgramArguments</key>
<array>
  <string>/bin/bash</string>
  <string>/Users/kim/journals/makeTodaySym.sh /Users/kim/journals</string>
</array>

I have also tried

<key>ProgramArguments</key>
<array>
  <string>/bin/bash</string>
  <string>/Users/kim/journals/makeTodaySym.sh</string>
  <string>/Users/kim/journals</string>
</array>

And now I get this

shell-init: error retrieving current directory: getcwd: cannot access parent directories: Operation not permitted
/bin/bash: /Users/kim/journals/makeTodaySym.sh: Operation not permitted

thanks to @jaume with great patience, he/she/they have helped me get to the point where I realized that the only thing that worked was to move away from the Documents folder in Catalina.

I did find this link https://discussions.apple.com/thread/250719819?answerId=251683647022#251683647022 suggesting to create a fake bash clone, but I didn't try.

Also a big thank you to @nohillside

One useful thing I learn is to load and unload plist without restarting laptop

first unload

launchctl unload ~/Library/LaunchAgents/com.test.today.plist

then load

launchctl load -w ~/Library/LaunchAgents/com.test.today.plist
19
  • 1
    Does the user under which the launchd job executes have write access to the directory?
    – nohillside
    Jun 10, 2020 at 5:40
  • Also, is this Catalina? Did you grant disk access?
    – nohillside
    Jun 10, 2020 at 5:41
  • @nohillside thanks. I have updated the question with answer to your questions
    – Kim Stacks
    Jun 10, 2020 at 5:48
  • 1
    Sounds like the same solution I found on the Apple website but I will wait for your solution
    – Kim Stacks
    Jun 10, 2020 at 8:48
  • 1
    @KimStacks After quite a bit of research, I found out that there's a better solution. If you move the script outside of ~/Documents and edit the .plist file accordingly, everything should work, see my answer for details. Could you try it and report back?
    – jaume
    Jun 10, 2020 at 12:14

2 Answers 2

3
+50

Analysis

After a long chat session, it turns out that the root of the problem was that bash can't fully access the Documents folder. The OP had shortened the actual path for makeTodaySym.sh: instead of being located in /Users/kim/journals, the script resides in a subfolder of ~/Documents.

The Documents folder is sandboxed, as explained in this Apple document:

In macOS, data in critical areas is itself sandboxed — which ensures that users remain in control of access to files in Desktop, Documents, Downloads and other areas from all apps, whether the apps attempting access are themselves sandboxed or not.

and bash can't read its contents from within the .plist file.

Two solutions

Place the script outside of ~/Documents

Interestingly enough, although bash can't read the contents of the Documents folder, it can write to it.

So one solution is to move makeTodaySym.sh outside of ~/Documents. For instance, if placed in /Users/kim/bin/makeTodaySym.sh, this should work:

<key>ProgramArguments</key>
<array>
  <string>/bin/bash</string>
  <string>-c</string>
  <string>/Users/kim/bin/makeTodaySym.sh /Users/kim/Documents/Apps/CompanyLevelApps/OILD/16-journals</string> 

(Tested on macOS 10.15.5 Catalina.)

Grant full disk access to bash

Another solution is give bash full disk access. Just add /bin/bash to System Preferences>Security & Privacy>Privacy>Full Disk Access.

Note that even with full disk access, permissions would prevent bash from reading arbitrary files in the file system, but you have one fewer level of protection.

(Tested on macOS 10.15.5 Catalina.)

Two suggestions

I'd suggest that you do the following two changes to your configuration:

Remove reference to working directory

I've noticed that setting a working directory in the .plist file:

<key>WorkingDirectory</key> 
    <string>/Users/kim/Documents/Apps/CompanyLevelApps/OILD/16-journals</string> 

causes this error:

job-working-directory: error retrieving current directory: getcwd: cannot access parent directories: Operation not permitted

Your script doesn't need the WorkingDirectory key to successfully create the symlink, so you may want to remove it to get rid of the error.

Create symlink with relative path

Your script creates the symlink:

ln -sf "$file" "$folder/today.md"

with an absolute path:

today.md@ -> /Users/kim/Documents/Apps/CompanyLevelApps/OILD/16-journals/2020-06-10 Wednesday.md

To may want to use:

ln -sf "$(basename "$file")" "$folder/today.md"

instead to create a relative symlink that is easier to read:

today.md@ -> 2020-06-10 Wednesday.md

Full path in plist file

It's important to note that providing the full path for makeTodaySym.sh (as explained in jksoegaard's answer) was a necessary change for the .plist to work properly, as relative paths are not supported.

4
  • i think the bounty needs a min of 24 hrs before awarding. thank you!
    – Kim Stacks
    Jun 10, 2020 at 16:59
  • awarded. thank you @jaume this is one of the best experiences I've ever had on SO!
    – Kim Stacks
    Jun 11, 2020 at 17:14
  • @KimStacks Hi Kim, that's very kind, I'm happy I could help! I've expanded the TLDR section in your answer to include additional information and a link to my answer. Feel free to edit it if you think it can be improved.
    – jaume
    Jun 12, 2020 at 6:06
  • 1
    It’s all good. Thanks for expanding on the TLDR
    – Kim Stacks
    Jun 12, 2020 at 9:22
2

You need to change this:

<string>./makeTodaySym.sh</string>

so that you refer the whole path to the file. That could for example be like this:

<string>/Users/kim/journals/makeTodaySym.sh</string>
1
  • Thank you. I have replaced it and unloaded and reloaded the plist. But it doesn't seem to create the new symlink. And after I wiped the stderr.log I still ahve the same error message after I relaunched the plist
    – Kim Stacks
    Jun 6, 2020 at 3:26

You must log in to answer this question.

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