Is it possible to use find + xargs in order to invoke more than one command? I am trying to find all files whose size is greater than 100 chars. and less than 1000 chars , change their permissions and print list of files into file. I can do it with exec e.g
find . -maxdepth 1 -size +100c -size -1000c -exec chmod a+r {} \; -print > testfile
But is there any way how to achieve this with xargs?
find . -maxdepth 1 -size +100c -size -1000c -print0 | xargs -0 -I '{}' chmod a+r '{}' -print >testfile
the last print won't execute or throws error. Is there a way to achieve it with xargs?
Best Answer
You don't need any of the GNUisms here (and you probably want a
-mindepth 1
to exclude.
), and you don't need to run onechmod
per file:(I've also added a
! -type l
because-size
would check the size of the symlink whilechmod
will change the permissions of the target of the symlink so it doesn't make sense to consider symlinks. Chances are you'd want to go further and only consider regular files (-type f
))That works here because
chmod
doesn't output anything on its stdout (which otherwise would end-up in testfile).More generally, to avoid that, you'd need to do:
So that
find
's stdout goes totestfile
butcmd-that-may-write-to-stdout
's stdout goes to the original stdout before redirection (as saved with3>&1
above).Note that in your:
testfile
would contain the files for whichchmod
has succeeded (the-print
being after-exec
means-exec
is another condition for that-print
, and-exec
succeeds if the executed command returns with a non-zero exit status).If you wanted to use
xargs
(here using GNU syntax), you could usetee
and process substitution:To save the output of
find
with NULs turned into newlines intotestfile
. Note however that thattr
command is running in background. Your shell will wait forxargs
(at least, most shells will also wait fortee
andfind
), but not fortr
. So there's a little chance thattr
has finished writing data totestfile
by the time the shell runs the next command. If it's more important that thetestfile
be fully written by then than all the permissions be modified, you may want to swap thexargs
andtr
commands above.Another options is to wrap the whole code above in:
That way, the shell will wait for
cat
and thatcat
will only exit when all the processes that have that file descriptor 3 open on the writing end of the pipe it reads (which includestr
,find
,tee
,xargs
) have exited.Another option is to use
zsh
globs here:Though you could run into a too many arguments errors if the list of files is very big.
find -exec +
andxargs
work around that by running severalchmod
commands if needed. You can usezargs
inzsh
for that.