chown -R exclude some directory
Solution 1:
chown -R admin $(ls -I content)
ls -I
will list all except specified pattern.
Solution 2:
In Linux the most general tool to do something to files meeting some criteria is find
. Few other answers base on the find … | xargs …
idea, which is robust only if it uses null-terminated strings. This means find … -print0 | xargs -0 …
, but these options are not required by POSIX.
With POSIX find
it's usually better to use -exec
than to pipe to xargs
. Personally I prefer -exec
even if I can safely use xargs
. Knowing that -exec
is also a test, so it can be used to build custom tests (example), it's good to be familiar with it anyway; and then there is no reason not to use it instead of xargs
. The real power of xargs
is its ability to parse strings with quotes and escaped characters; but this is hardly ever useful when reading from find
, almost always it's harmful. Non-POSIX options like -0
and --no-run-if-empty
can make xargs
a good companion of find … -print0
, but still the good POSIX -exec
is (almost?) always at least as good.
Your problem can be solved by
find /home/admin/web/public_html \
-path /home/admin/web/public_html/content -prune \
-o -exec chown admin {} +
It works like this: if the path is …/content
then do not descend into it (-prune
); otherwise (-o
) execute chown admin
on the file (note: directory is also a file).
Notes:
-
Do not use
chown -R
here. The first file tested is/home/admin/web/public_html
and if you usechown -R
on it then nothing will be excluded. -
-exec chown … {} +
can and will pass multiple paths tochown
, while-exec chown … {} \;
would pass just one (so there would be onechown
spawned per file). The syntax with+
reduces the number of spawnedchown
processes, this speeds things up. Even thenfind
will spawn more than onechown
process if the number of files is too large for a single command line (compare "argument list too long"). Note it works becausechown
can take multiple paths; some tools cannot and for them the syntax with+
is out of the question. -
-path
matches against the entire path. The path is whatfind
thinks the path is, not necessarily the canonical path. If the starting path is/home/admin/web/public_html
then every path tested will start with this string; but if the starting path is./
then every path tested will start with this string. In the former case-path /home/admin/web/public_html/content
will never be true, even ifrealpath ./
prints/home/admin/web/public_html
, because the relevant directory will be identified by the string./content
and this is the string you would want to match with-path
. In general you need to adjust the argument of-path
to the starting location(s) (or use wildcards maybe). -
If you need to exclude multiple patterns then follow this example:
find . \ -path ./content -prune \ -o -path ./foo/bar -prune \ -o -path '*/baz' -prune \ -o -exec chown admin {} +
which can be compacted to
find . \ \( -path ./content \ -o -path ./foo/bar \ -o -path '*/baz' \ \) -prune \ -o -exec chown admin {} +
where parentheses are important.
With
-regex
you may be able to combine multiple patterns into one (example). This test is not required by POSIX though. -
Other tests (e.g.
-name
or even-exec
) can be used to exclude files.