Home > Software design >  How to change all folders and files permessions base on folder name?
How to change all folders and files permessions base on folder name?

Time:02-26

For exemple we have folders named with permission numbers 555 or 700 or 777... how can we take the file name and change all the subfolders and files with permissions based on the folder name ? so if we apply it on the folder 555 the current folder and everything inside will have permission as 555 i've tried

find . -name "[0-9][0-9][0-9]" -type d | xargs chmod -Rv [0-9][0-9][0-9]

but it only takes the first folder name and apply it on everything it i want it to treat each folder name ( named withe permission) seperately thank you.

CodePudding user response:

Not sure understand the question.

Need sample input and sample output to understand.

Suggesting following solution:

 dir_name="555"; chmod -R "$dir_name" $(find . -path "*$dir_name*")

Explanation

dir_name="555"; : Assign a variable dir_name that holds the directory name 555 and the chmod permission value 555

$(find . -path "*$dir_name*"): List all files under current directory having 555 somewhere in their path.

chmod -R "$dir_name" : Chmod command using the value of dir_name 555

CodePudding user response:

I'd use something like this.

find . -type d -name '???' -printf '%f\n' | xargs -I'{}' chmod -R  '{}' '{}'
  • -type d -- find only directories.
  • -name ??? -- this will cover directories named 555, 700, 777, etc
  • printf '%f\n' -- print only directory's name.

To be really safe, I would add another option (-maxdepth):

find . -maxdepth 1 -type d -name '???' -printf '%f\n' | xargs -I'{}' chmod -R  '{}' '{}'
  • maxdepth 1 -- Don't do any search on subfolders.

CodePudding user response:

i've tried find . -name "[0-9][0-9][0-9]" -type d | xargs chmod -Rv [0-9][0-9][0-9] but it only takes the first folder name and apply it on everything it i want it to treat each folder name ( named withe permission) seperately

Your attempt is wrong in several ways, among them:

  1. The [0-9][0-9][0-9] pattern matches names that include characters that are not octal digits.

  2. The [0-9][0-9][0-9] pattern will be expanded by the shell when it parses the command. If the expansion is successful, then the first matching name will give the mode to apply. If the expansion is not successful then (by default) the pattern itself will be passed through to chmod, which will reject it as an invalid mode.

  3. By default, the xargs command will take as many inputs as it can to form arguments to one command. So in your example command, if find identifies folders 700, 555, 755, and 400 then the xargs will end up executing something like this:

    chmod -Rv <... expansion of [0-9][0-9][0-9] ...> 700 555 755 400
    

    Even in the event that the pattern expanded to nothing (which could happen under slightly different circumstances) you have a result similar to before: the first directory name would provide the mode, and all the others would be updated to that mode.

This variation should do what you want:

find . -name "[0-7][0-7][0-7]" -type d |
  sed 's,^.*/\([^/]*\)$,\1\n\0,' |
  xargs -r -l2 chmod -Rv

The sed command takes each path emitted by find, extracts the base name, and puts that on a separate, preceding line. For example, if one of the lines find emits is

./subdir/755

then sed will change that to

755
./subdir/755

. That is, the mode to apply and the directory to which to apply it.

Then the -l2 option to xargs tells it to use (at most) two input lines in forming each chmod command, so you will end up with a series of commands of the form

chmod -Rv 755 ./subdir/755

The -r option to xargs is a nicety that tells it to avoid executing any commands at all if no lines are read from the standard input.

Addendum: the sed expression in more detail

[Note: I have slightly simplified the sed command given in the original version of this answer.]

The sed command ...

  sed 's,^.*/\([^/]*\)$,\1\n\0,'

... processes each input line according to the given expression, a substitute command with comma (,) delimters.

  • The target pattern is ^\(.*/\)\([^/]*\)$. This matches
    • a sequence starting at the beginning of the line (^),
    • matching any number of any character .*,
    • followed by a slash (/) character,
    • followed by any number of any character other than slash ([^/]*)
    • running to the end of the line ($).
  • The part after the last slash is captured as a group.
  • the replacement text is
    • the contents of the first (only) capture group (\1), followed by
    • a newline (\n), followed by
    • the whole match (\0), which will be the original line because the match is anchored to both the beginning and end of the line.

sed will match each input line against the target pattern. Any line containing at least one slash will match, and every line emitted by the given find command will satisfy that criterion. The whole match (which will be the whole line) will be replaced by the given replacement, consisting of two lines -- one containing the tail of the original line following the last slash, and the other containing the whole original line.

  • Related