-> find .. -name bin -exec for file in {}/* ; do echo $file ; done \;
-bash: syntax error near unexpected token `do'
What is the proper syntax for this command ?
-> find .. -name bin -exec for file in {}/* ; do echo $file ; done \;
-bash: syntax error near unexpected token `do'
What is the proper syntax for this command ?
To use multiple statements, such as a for-loop, as the argument to -exec, one needs to invoke a shell, such as bash, explicitly:
find .. -name bin -exec bash -c 'for file in "$1"/* ; do echo "$file" ; done' none {} \;
This is safe even for filenames that contain spaces or other hostile characters.
bash -c worksOne can invoke bash with a command of the form:
bash -c some_complex_commands arg0 arg1 arg2 ...
In this case, bash will execute whatever is in the string some_complex_commands. Those commands can make use of the usual shell positional parameters. The first argument after command, arg0 above, is assigned to $0, the second to $1, the third to $2, etc.
When one executes a normal shell script, $0 is the name of the script and $1 is the first argument that appears on the command line. In keeping with that tradition, the bash -c command was written to assign the file name, {} in find's notation, to $1. Since this script does not have a sensible name, none is assigned as a placeholder to $0.
It looks like you've got things reversed from what you want. Try this:
for f in `find .. -name bin`
do
echo $f
done
find therefore it outputs founded elements like loop by itself
– Costas
Apr 01 '15 at 18:28
$file is never set to anything. Perhaps you don’t understand what James was trying to do.
– Scott - Слава Україні
Apr 01 '15 at 18:29
You can approximate the output of your pseudo-code there with find primitives as is:
find .. -path \*/bin/\* ! -name .\*
...which should print only files/dirs with names that do not begin with a . and which are rooted at some level both in the parent directory, and, at some greater degree, in a dir named /bin.
In general I can think of all kinds of practical purposes for looping in a find -exec child process, but not a one in which I could consider it practical to do shelld glob on an argument passed by find. To do the same thing your pseudo-code does with printf - because its use can guarantee literal translation of arguments to output - you might do...
find .. -type d -name bin -exec sh -c '
printf %s\\n "$0/"*' {} \;
...which does the printing and the globbing without the for loop. One difference between this and your example command, though, is that without the -type d specification and type of result matching the name bin will be echod - and so you're highly likely to see a lot of bin/* being written to stdout. Of course, even w/ -type d, there's no guarantee that the * will resolve - an empty directory or one containing only .files will render no matches and so you might see it anyway.
Note also that the example pseudo code, because it uses the {} \; primitives might be a lot slower than some other ways. We'll try the printf thing again like:
find .. -type d -name bin -exec sh -c '
for d do printf %s\\n "$d/"*; done' -- {} +
...which still risks the empty glob case but instead of -execing a shell per match, it rather gathers as many arguments as it might reasonably pass off to another process at exec time and passes the lot to sh in "$@" its positional parameter array - which we can loop over with for d do printf....
Now if you wanted to do something other than just print results - which is what I would typically consider useful about looping in an -exec statement - you can fallback to the earlier -path example and combine it with -exec like...
find .. -path \*/bin/\* -exec sh -c '
for arg do : something with "$arg"
done' -- {} +
find .. -path '*/bin/*' ! -name . -prune ! -type d which should print only files other than type directory which reside in a directory named ../(*/)*bin.
– mikeserv
Apr 02 '15 at 06:09