cp -R {target} {dest} gives ‘Operation not permitted’ error during background backup script execution
See the code from com.user.backup.plist and backup-script.sh below.
I tried to go to System Settings → Privacy & Security → Full Disk Access to grant access to the backup script ~/backup-script.sh which is an executable (-rwxr-xr-x@) that is executed by ~/Library/LaunchAgents/com.user.backup.plist every Saturday at 03:00 h but after using ⌘⇧. to show all files, I still cannot select it. My next idea would be to try to grant launchd itself full disk access, but this seems like a Bad Idea™ security-wise.
Besides helping with my system here, which is good when ran from the command line –
What are people doing to backup particular directories besides just using Time Machine?
sw_vers
% :: sw_vers 13:15:42 (130)
ProductName: macOS
ProductVersion: 15.6.1
BuildVersion: 24G90
~/Library/LaunchAgents/com.user.backup.plist
<?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.user.backup</string>
<key>ProgramArguments</key>
<array>
<string>/Users/user/backup-script.sh</string>
</array>
<key>StartCalendarInterval</key>
<dict>
<key>Hour</key>
<integer>3</integer>
<key>Minute</key>
<integer>0</integer>
<key>Weekday</key>
<integer>6</integer>
</dict>
<key>StandardErrorPath</key>
<string>/tmp/backup.err</string>
<key>StandardOutPath</key>
<string>/tmp/backup.out</string>
<key>RunAtLoad</key>
<false/>
</dict>
</plist>
~/backup-script.sh
#!/bin/bash
### ----------------
### Disk Capacities
### ----------------
### A management task should be to prune these directories, and then test the
### /Users/user/cleanup-script.sh --dry-run (using the dry-run flag) and tail -f to follow logfiles
### ----------------
### Configuration
### ----------------
# Define directories and/or files to back up
# _Exclude_ trailing / from directories for cp -R's expected behavior!
BACKUP_TARGETS=(
"target1"
"target2"
)
### ----------------
### Configuration
### ----------------
# Define external volumes
# Intentionally withheld final "https://apple.stackexchange.com/"
VOLUMES=(
"/Volumes/External/Backups"
"/Volumes/Samsung USB/backups"
)
### ----------------
### Configuration
### ----------------
### Logging
### ----------------
# Set the logfile directory
# If on startup this directory doesn't exist, the script will quit
# and instruct the administrator to specify the LOGFILE_DIR
# and ensure that other configuration variables like BACKUP_DIRS
# are properly set
LOGFILE_DIR="/Users/user/backup-cleanup-logs"
if [ ! -d "$LOGFILE_DIR" ]; then
error_LOGFILE_DIR_not_exists=$(cat <<EOF
Error: \$LOGFILE_DIR is set to $LOGFILE_DIR that does not exist.
Review configuration of $0, setting \$BACKUP_DIRS and \$LOGFILE_DIR
EOF
)
echo "$error_LOGFILE_DIR_not_exists"
exit 1
fi
# Define the date format for log files and backup naming
DATE=$(date +%Y-%m-%d)
# Define log file
LOGFILE="$LOGFILE_DIR/backup-log-$DATE.log"
# Function to perform backup
# Rename any hidden files prepended by '.' to "dot_" followed by their proper name
backup() {
for TARGET in "${BACKUP_TARGETS[@]}"; do
for VOLUME in "${VOLUMES[@]}"; do
BACKUP_NAME="$(basename "$TARGET"|sed 's/\./dot_/')-$DATE"
BACKUP_PATH="$VOLUME/$BACKUP_NAME"
if cp -R "$TARGET" "$BACKUP_PATH"; then
echo "Backup of $DIR to $BACKUP_PATH successful." >> "$LOGFILE"
else
echo "Error backing up $DIR to $BACKUP_PATH." >> "$LOGFILE"
fi
done
done
}
# Run backup function
backup
echo "Finished backing up..."
