25

I need to set read and write permissions for root user to directory subfolderN and all its parent folders till root.

I can do it by hands:

$ sudo chmod +rx /root/subfolder1/subfolder2/subfolderN
$ sudo chmod +rx /root/subfolder1/subfolder2
$ sudo chmod +rx /root/subfolder1
$ sudo chmod +rx /root

But if N is big I am tired. How to do automatically by one command?

1
  • 1
    You should really not make /root world readable. Jun 15, 2018 at 13:23

4 Answers 4

33

This can be done easily in the shell, starting in the subdir and moving upwards:

f=/root/subfolder1/subfolder2/subfolderN
while [[ $f != / ]]; do chmod +rx "$f"; f=$(dirname "$f"); done;

This starts with whatever file/directory you set f too, and works on every parent directory, until it encounters "/" (or whatever you set the string in the condition of the loop to). It does not chmod "/". Make sure both f and the directory in the condition of the loop are absolute paths.

6
  • Nice, I knew I was complicating things needlessly with Perl.
    – terdon
    Sep 14, 2013 at 4:02
  • But what if f is a relative path, and I want to stop at what it is relative to instead of /?
    – Tim
    Jun 15, 2018 at 13:33
  • @StéphaneChazelas Thanks. If $f is foo/bar, will $f ever change to .? Yes dirname does it. Thanks
    – Tim
    Jun 15, 2018 at 13:37
  • 2
    @Tim convert relative path to absolute path before storing in f using command "f=`readlink -f <relative_path>`" Apr 15, 2019 at 11:03
  • 1
    Remember to use absolute path. I used short link path and had a lot problems. Finally get it back to normal. Feb 20, 2020 at 20:21
8

With csh, tcsh, ksh, zsh, bash, fish or yash -o braceexpand:

sudo chmod +rx /root{,/subfolder1{,/subfolder2{,/subfolderN}}}

With zsh:

f=/root/subfolder1/subfolder2/subfolderN
until [[ $f = / ]] {chmod +rx $f; f=$f:h;}

Or you could define a glob qualifier function like:

explode() {
  reply=()
  until [[ $REPLY = [./] ]] {
    reply+=$REPLY
    REPLY=$REPLY:h
  }
}

To be used for instance as:

$ echo chmod +rx subfolder1/subfolder2/subfolderN(+explode)
chmod +rx subfolder1 subfolder1/subfolder2 subfolder1/subfolder2/subfolderN  

Note that chmod +rx is affected by the umask. If your umask doesn't include 007, it would make the /root directory world-readable and accessible which is a bad idea. /root is typically for the super-user's private things, it's a bad idea to expose it.

3
  • Could you explain what the leading , in {,/subfolder} does?
    – terdon
    Sep 14, 2013 at 14:28
  • It creates an alternation where the first string is empty and the second is /subfolder; so /root{,/subfolder} produces /root and /root/subfolder
    – tripleee
    May 25, 2018 at 5:15
  • Notably this is not portable to POSIX sh
    – tripleee
    May 25, 2018 at 5:15
2

I don't know what you are trying to do, but is better than you don't take the recursive lightly. That said, read the actual answer:

Umm... why not just use recursive.

sudo chmod -R +rx /root

Or if you don't like it, you can give chmod several directories:

sudo chamod +rx /root /root/subfolder1 /root/subfolder1/subfolder2 /root/subfolder1/subfolder2/subfolderN
3
  • 6
    That's not nearly the same operation, though. chmod -R /root changes everything under /root — including regular files and all directories. The question is about changing one chain of directories only. Sep 14, 2013 at 4:04
  • @200_success but that's not the only answer ;)
    – Braiam
    Sep 14, 2013 at 4:08
  • 1
    The question is not about recursion, but how to set permissions on a chain of parent folders to allow selective access to a subfolder. Saying that it's not the only answer is like saying driving a bus through your wall is another way to make a door.
    – jmc
    Nov 13, 2018 at 15:13
2

Well, you could do something slightly more complex like:

echo "/root/subfolder1/subfolder2/subfolderN" | 
 perl -anF'/' -e 'while($#F>0){@b=join("/",@F);`chmod +rx @b`; pop @F}' 

To see what this will do, replace the chmod call with print:

$ echo "/root/subfolder1/subfolder2/subfolderN" | 
 perl -alnF'/' -e 'while($#F>0){@b=join("/",@F);print "chmod +rx @b"; pop @F}' 
chmod +rx /root/subfolder1/subfolder2/subfolderN
chmod +rx /root/subfolder1/subfolder2
chmod +rx /root/subfolder1
chmod +rx /root

You must log in to answer this question.

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