81

I need to use chmod to change all files recursivly to 664. I would like to skip the folders. I was thinking of doing something like this

ls -lR | grep ^-r | chmod 664

This doesn't work, I'm assuming because I can't pipe into chmod Anyone know of an easy way to do this?

Thanks

Ori
  • 4,961
  • 10
  • 40
  • 39
  • You might be interested to know that you can make directories executable without making files executable (e.g. `chmod -R +X`, with a capital X). – Brōtsyorfuzthrāx Oct 25 '22 at 06:45

5 Answers5

125

A find -exec answer is a good one but it suffers from the usually irrelevant shortcoming that it creates a separate sub-process for every single file. However it's perfectly functional and will only perform badly when the number of files gets really large. Using xargs will batch up the file names into large groups before running a sub-process for that group of files.

You just have to be careful that, in using xargs, you properly handle filenames with embedded spaces, newlines or other special characters in them.

A solution that solves both these problems is (assuming you have a decent enough find and xargs implementation):

find . -type f -print0 | xargs -0 chmod 644

The -print0 causes find to terminate the file names on its output stream with a NUL character (rather than a space) and the -0 to xargs lets it know that it should expect that as the input format.

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • This is great for GNU find but unfortunately -print0 and xargs -0 are not standard, and don't work e.g. on Solaris. So in that case use one of the other solutions. – mark4o Jul 22 '09 at 16:49
  • 2
    I can confirm that this method works on Mac OSX (10.9 at least). – Anthony F Jan 24 '14 at 20:33
  • @mark4o, you're not limited to using the braindead versions that come with Solaris. One great advantage of FOSS is that you can port it to any close-enough (UNIXy) OS. I frequently did that for AIX per-version-5L. – paxdiablo Dec 04 '14 at 13:47
  • 1
    If you mean have too _many_ arguments for `chmod`, that's not an issue. `xargs` batches things up intelligently. – paxdiablo Jan 14 '15 at 01:01
  • @paxdiablo You're right. I did not word my comment correctly. Xargs has a maximum command length. If you are using your recommended method, you could hit this limit. It's unlikely, but possible. Check `getconf ARG_MAX` to see this limit. – MikeNGarrett Jan 17 '15 at 03:37
  • this worked great on Mac OS X (10.9). I tried so many things before this. – echo Apr 17 '15 at 00:11
  • well explained, and portable enough for my needs, even if it's not 100% posix – code_monk Sep 07 '15 at 20:59
  • We might need to set `-L num` option for `xargs` in cases where we have too many files and run into `Argument list too long` issue trying to do a single `chmod` on all of them. – codeforester Jan 20 '17 at 01:02
  • 1
    @codeforester, `xargs` *already* batches up files so that they don't exceed the argument length limit. The `-n/-L` options simply allow further arbitrary limits on the batch size. – paxdiablo Jan 20 '17 at 01:33
  • @paxdiablo - great. I have deleted my answer. – codeforester Jan 20 '17 at 01:35
36

Another way to do this is to use find ... -exec ... as follows:

find . -type f -exec chmod 644 {} \;

The problem is that the -exec starts a chmod process for every file which is inefficient. A solution that avoids this is:

find . -type f -exec chmod 644 {} +

This assembles as many file names arguments as possible on the chmod processes command line. The find ... | xargs ... approach is similar; see the accepted answer.

For the record, using back-ticks is going to break if there are too many files to be chmoded, or the aggregated length of the pathnames is too large.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
22

My succinct two cents...

Linux:

$ chmod 644 `find -type f`

OSX:

$ chmod 644 `find . -type f`

This works to recursively change all files contained in the current directory and all of its sub-directories. If you want to target a different directory, substitute . with the correct path:

$ chmod 644 `find /home/my/special/folder -type f`
Arman H
  • 5,488
  • 10
  • 51
  • 76
2

via http://www.linuxquestions.org/questions/aix-43/chmod-recursion-files-only-208798/?s=a70210fb5e5d0aa7d3c69d8e8e64e3ed

"find . -type f -print | xargs chmod 444 "shoud work, isn't it ? If not, find . -print >myfile.sh and vi myfile.sh removing the directories (they should not be soo many), and then 1,$s/^/chmod 444/ and sh myfile.sh.

b0x0rz
  • 3,953
  • 8
  • 52
  • 82
2

with GNU find

find /path -type f -exec chmod 644 {} +;

amra
  • 16,125
  • 7
  • 50
  • 47
ghostdog74
  • 327,991
  • 56
  • 259
  • 343