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.
Related videos on Youtube
Mitra
Updated on September 18, 2022Comments
-
Mitra over 1 year
I want to exclude some large content directory
I'm Using it to chown Directory
chown -R admin /home/admin/web/public_html
is there anyway to exclude a subdirectory under html
Like:
chown -R admin exclude=/home/admin/web/public_html/content /home/admin/web/public_html
Something like that
Thanks
-
Mitra about 6 yearsThanks, for your answer. I had try that just like this.
find . -type d \( -path contents -o -path admin/logs -o -path admin/data/backup -o -path admin/data/conversion -o -path admin/smarty/cache -o -path admin/data/engine/storage -o -path 78 -o -path 976 -o -path tmp \) -prune -o -print | xargs chown -R admin
-
Mitra about 6 yearsBut Its also taking long time
-
Mitra about 6 yearsShould I add
-not
-
emaV about 6 yearsIf you have a long list then a better approach is to create a file and grep the result. So let say that the exclusion list is in the
zzNotNowChownPlease
file. Then:find . -type d |grep -fv zzNotNowChownPlease |xargs chown -R admin
Should work. Just test the find+grep before. -
Kamil Maciorowski over 3 yearsWarning: this answer is badly flawed. Do not use it. Maybe unless you understand its flaws and can tell they won't do any harm in your particular case. But then it's still like using a gun as a hammer: not a wise idea, even if unloaded. The flaws: (1) Parsing
ls
is wrong. (2) Bash pitfall number 1 (you havechmod
instead offor
but the problems are the same). (3) Possibly "argument list too long". -
Kamil Maciorowski over 3 yearsThe command is a no-op. The first object tested by
find .
is.
. For it-type d
is true,-not -path …
is true,-prune
is true,-print0
is not evaluated. Nothing more is tested because of-prune
for.
. Thus the stdin ofxargs
is empty and the tool runs justchown admin
which is invalid. Besides, in general if you start from.
then each and every path tested byfind
will start with./
or be exactly.
; so I can tell in advance that-path /home/admin/web/public_html
will always be false (in other words:-path
does not performrealpath
before testing). -
Kamil Maciorowski over 3 yearsProblems: (1) This will exclude every file named
content
, possibly somewhere deep in the directory tree, not only the specific directory in question. (2) This will still descend into the "excluded" directory andchown
files in it. Usually "to exclude a directory" means "to exclude a directory along with its content". (3)xargs
(even with-I
) interprets quotes and backslashes. Newline characters, quotes and backslashes may appear in pathnames, they will cause the solution to fail. -
Giacomo1968 almost 3 years-1 How does this answer improve on what has already been posted in the past 3 years since this question was originally posted?
-
Nick Fan almost 3 years@Giacomo1968 it works for the purpose : i want to chown recursively but exclude specific sub directory. mindepth 1 prevent the parent directory , which if included the -R option will cause chown for all subdirectories, so fail for exclude sub directory. maxdepth 1 only first level sub directory and files for result, with -R option chown , it will exec exactly what we want. -print0 ok for debug or dryrun
-
Giacomo1968 almost 3 yearsWell, happy this works for you. But this is not an answer that adds new insight that the other answers provide. Please remember this site is not a message board and just posting a “Me too!” answer with slight variation is not of real value to others.
-
Max Muster almost 3 yearscan't find the "-o" in the man page