MacOS – Mac Big Sur home folder permissions: Read-only file system when renaming files

big surmacospermissionsipterminal

UPDATE #2

I was able to successfully rename the files using sed:

for f in *.Rdat; do mv $f $(echo $f | sed "s/PCC-//"); done

UPDATE
I discovered I can rename individual files:

mv 'PCC-ASR-L.Rdat' 'ASR-L.Rdat'

So evidently the problem occurs only when trying to batch rename in a for loop. I would still like to understand why.

ORIGINAL POST

After upgrading to Big Sur from Catalina, I tried to use the terminal to rename some files in a subfolder of my Home folder. I had created and used the subfolder before upgrading. Specifically, I tried renaming a group of Rdat files using a bash for loop. I could do this under Catalina, but now I get an error. Here, I am trying to replace 'PCC-' in each file name with an empty string (i.e. ''):

for f in *.Rdat; do mv $f ${f/PCC-//}; done

This yields an error for every file, like this (for file PCC-ASR-H.Rdat):

mv: /ASR-H.Rdat: Read-only file system

This seems strange because as owner of the folder I have write permissions:

drwxr-xr-x    8 mike  staff   256 Nov 21 15:04 Rdatafiles

And I have write permissions for the files in the folder (example):

-rw-rw-r--@ 1 mike  staff  10926 Dec  4 18:26 PCC-ASR-H.Rdat

I tried disabling SIP in Recovery Mode:

csrutil disable

But the problem remains. Is it possible to make subfolders of the home folder writeable under Big Sur? Are there some additional changes I need to make to the system (i.e. permissions) to enable write access? Or do I now need to move my work files out of Home and into, say, Home/Documents, to avoid this issue?

Best Answer

The problem is the double forward-slash in ${f/PCC-//}. Unlike a sed substitution pattern, there's no / at the end of the replacement pattern (it's terminated by }), so the extra / is taken as the replacement string. This turns e.g. "PCC-ASR-L.Rdat" into "/ASR-L.Rdat", which (because of the "/") is at the root of the filesystem... which is read-only.

When I'm doing things like batch renames, I also often don't get everything right on the first try, so I tend to do a dry run with echo in front of the mv (or cp or rm or...) command first, so I can see what's going to happen before actually running it. I also strongly recommend using mv -i or mv -f, so if there's any sort of naming conflict it won't just silently and irreversibly overwrite files. Also, putting double-quotes around variable references is a good idea, in case any filenames contain weird characters.

So my dry run would look something like this:

for f in *.Rdat; do echo mv -i "$f" "${f/PCC-/}"; done

...and if that looked right, I'd hit up-arrow to get it back, delete the "echo", and re-run it for real.

If you need to troubleshoot in even more detail, using set -x before the command will show what the shell thinks is going on (i.e. what the command looks like after substitutions are performed) in cases like this.