-exec utility_name [argument ...] ;
Further, the GNU man page says that such a construction "might need to
be escaped (with a `\') or quoted to protect them from expansion by
the shell." Might? I don't see how to use the unquoted semicolon
without getting the error message
find: missing argument to `-exec'
My feeling would be that the POSIX standard has a typo, that ';'
should read '\;'. But... the -ok description is the same!
Any thoughts? Thanks in advance.
If you execute it from a C program you don't need the backslash:
execlp("find", "find", ..., "-exec", ..., ";", (char*)0);
Escaping is part of the shell's syntax, not the command's syntax.
--
Barry Margolin, bar...@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
*** PLEASE don't copy me on replies, I'll read them in the group ***
If you don't mind, could you elaborate a little (maybe recommend
insightful reading material)? For instance, why are command syntax and
shell syntax different? Regardless of possible interfaces with C,
isn't find, after all, a shell command?
Cheers,
Eze
No, find is a program. The shell is one way to run programs, but you
can also run them from C programs, perl scripts, python scripts, etc.
All commands are separate programs, unless they are listed as builtins
in your shell documentation, so they can have whatever rules their
author chose for interpreting their own arguments. But...
They can only see the arguments the shell gives them. A semi-colon
is interpreted by the commonly used shells as a command separator,
so they won't give it to the program as an argument unless you escape
it somehow. ';' is probably just as good as \; .
I said "probably", the find documentation says "might", because we
don't know what you choose to use as a shell, or what other shells
might be in common use in the future.
The C interface is not "possible", it is the low-level method used by
any program (including shells) which wants to run another program. It
just sends character strings as the arguments, and doesn't care what's
in them. A shell wants to provide you with a powerful interface, so it
has to use some special characters to do that. So you need a way to hide
them from the shell when they are meant for the program.
> No, find is a program. The shell is one way to run programs, but you
> can also run them from C programs, perl scripts, python scripts, etc.
One of the great things about the Unix shell is that it's trivial to
write a program that accepts meta-characters are arguments, like
myprogram *.html
> Thanks for your reply, Barry. I had the feeling a widespread typo was
> not very reasonable. Oh boy, just when I thought I was finally
> reaching a full understanding of quotes in the shell...
>
> If you don't mind, could you elaborate a little (maybe recommend
> insightful reading material)? For instance, why are command syntax and
> shell syntax different?
The syntax of find (or any other command) does *not* depend on
whether you run it through the shell or from another C program.
It's just that, when you run it through the shell, there is
another layer of interpretation.
If you call execl("/usr/bin/somecommand", "somecommand", "a b", ";")
from a C program, the somecommand process will see two arguments
beyond argv[0] : "a b" and ";".
If you type "somecommand a b ;" at the shell prompt, the shell
will interpret the space between a and b as an argument separator
and the semicolon as a command terminator. It will create a
somecommand process with two arguments beyond argv[0] : "a" and
"b". The semicolon does not appear at all because the shell took
it for itself.
To make the shell run somecommand with the arguments "a b" and
";", you have to quote the characters that are special to the
shell. There are many ways to do that. Here are three :
somecommand a\ b ';'
somecommand a' 'b ";"
somecommand "a "'b' \;
The samecommand process has no way of knowing by which of those
command lines it was run, because they all result in the shell
calling exec("/usr/bin/somecommand", "somecommand", "a b", ";").
It's like that for wildcards too, BTW. Under Unix, wildcard
expansion is normally performed by the shell, contrary to
operating systems like MS-DOS where wildcard expansion is done
by the command. When you type "somecommand *.c", the somecommand
process sees E.G. "main.c", "util.c", "util2.c", not "*.c". The
advantage of this way of doing things is that it guarantees that
wildcards work
1) with all programs,
2) at minimal cost,
3) in the same way for all programs.
> Regardless of possible interfaces with C, isn't find, after
> all, a shell command?
find(1) -- and the other so-called "shell commands" that are not
shell built-ins -- do not in any way depend on a shell. You run
them by exec()-ing their binary. They do not know or care
whether that exec(2) call was issued by a shell or by any other
kind of program.
--
André Majorel <URL:http://www.teaser.fr/~amajorel/>
"After 15 minutes, I wanted to marry her. After a half hour, I completely
gave up the idea of snatching her purse." -- _Take the Money and Run_
//Others have given explanations, perhaps some examples would also
help
//clarify.
$ >foo
//In our first example, we use perl, with a bare semicolon (;) as the
//last argument to find(1) (in this case we first use the space
//character to split our arguments):
$ perl << \__EOT__
> exec(split(/ /,q(find . -type f -name foo -exec ls -on {} ;)));
> __EOT__
-rw------- 1 1003 0 Nov 26 01:43 ./foo
//Here we use a common shell, and use strace(1) to see how the shell
//execve(2)s the command - note that the last argument to find(1) is a
//bare semicolon (;), the backslashes (\) having already been stripped
//by the shell.
$ strace -e trace=execve find . -type f -name foo -exec ls -on \{\} \;
execve("/usr/bin/find", ["find", ".", "-type", "f", "-name", "foo", "-
exec", "ls", "-on", "{}", ";"], [/* 23 vars */]) = 0
-rw------- 1 1003 0 Nov 26 01:43 ./foo
--- SIGCHLD (Child exited) @ 0 (0) ---
//And an example in C. Here again, the last argument to find is again
a
//bare semicolon (;).
$ cat foo.c
#include <unistd.h>
main(argc,argv,envp)
int argc;
char *argv[];
char *envp[];
{
char *foo[12];
foo[0]="find";
foo[1]=".";
foo[2]="-type";
foo[3]="f";
foo[4]="-name";
foo[5]="foo";
foo[6]="-exec";
foo[7]="ls";
foo[8]="-on";
foo[9]="{}";
foo[10]=";";
foo[11]=(char *)0;
execve("/usr/bin/find", foo, envp);
};
$ cc foo.c && ./a.out
-rw------- 1 1003 0 Nov 26 01:43 ./foo
$
Another example:
xargs env << \E
"find" . -ty\pe
f -name 'foo'
"-exec" ls -on {} ;
E
xargs treats blanks, backslashes, single and double quotes
specially (thought not in the same way as shells) but the ";"
character is not special to it.
--
Stéphane