if command in find -exec
Solution 1
First, your snippet executes the command
echo {} : ;if [ -f {} ]; then echo file; else echo directory;fi
because it needs its output to evaluate the command substitution. Since there is no file named {}
, this produces the output
{} :
directory
Then the find
command is executed with the arguments -exec
, echo
, {}
, :
, directory
, so for every file, it outputs the file name followed by a space and : directory
.
What you actually want to do is to execute the shell snippet echo {} :; …
on each file found by find
. This snippet must be executed by a shell spawned by find
, not by the shell that starts find
, since it is receiving data from find
on its command line. Therefore you need to instruct find
to run a shell:
find -exec sh -c 'echo {} : ;if [ -f {} ]; then echo file; else echo directory;fi' \;
This is better, but still not right. It'll work with some (not all) find
implementations if your file names don't contain any special characters, but since you are interpolating the file name in a shell script, you allow file names to execute arbitrary shell commands, e.g. if you have a file called $(rm -rf /)
then the command rm -rf /
will be executed. To pass file names to the script, pass them as separate arguments.
Also the first echo
prints a newline after the colon. Use echo -n
(if your shell supports it) or printf
to avoid this.
find -exec sh -c 'printf "%s :" "$0"; if [ -f "$0" ]; then echo file; else echo directory; fi' {} \;
You can use -exec … {} +
to group shell invocations, which is faster.
find -exec sh -c 'for x; do printf "%s :" "$x"; if [ -f "$x" ]; then echo file; else echo directory; fi; done' _ {} +
Solution 2
Another way for executing if; then; else; fi
together with find
is:
find |
while read p; do if [ -f "$p" ]; then echo file; else echo directory; fi; done
Related videos on Youtube
Esref
Updated on September 18, 2022Comments
-
Esref almost 2 years
I was just trying to list all directories and files under current directory and also write if they are file or directory with the following command:
find -exec echo `echo {} : ;if [ -f {} ]; then echo file; else echo directory;fi` \;
I know it is a silly command, I can use other things like
-type f
or-type d
, but I want to learn why that piece of code did not work as I expected. It just prints directory to all of them. For example while output offind
is:. ./dir ./dir/file
output of my code is :
. : directory ./dir : directory ./dir/file : directory
And output of
echo `echo dir/file : ;if [ -f dir/file ]; then echo file; else echo directory;fi`
is
dir/file : file
I am working on
Ubuntu 14.10
and usingfind (GNU findutils) 4.4.2
-
Costas over 9 years
find -exec bash -c 'echo -n "{} : ";if [ -f "{}" ]; then echo file; else echo directory;fi' \;
-
Esref over 9 yearsThanks @Costas but I know that using bash or sh I can achieve my initial goal, but now I want to understand why if behaves different with the exec parameter.
-
Esref over 9 yearsI already tried that and it gives the same output. find -exec echo
echo "{}" : ;if [ -f "{}" ]; then echo file; else echo directory;fi
\;
-
-
gerlos about 6 yearsCool solution. It avoids complex quote patterns and subshell complications. You may have previously defined a shell function, and execute it on the files matching the "if" condition.