0

This works

find ./ -iname '*.c' -o -name '*.h' -o -name '*.l' -exec grep -irn test1 {} \;

If I combine -exec with ls then it tells me that is improper option.

#ls -exec touch {} \;
ls: invalid option -- 'e'
Try 'ls --help' for more information.

Is my understanding correct that -exec option is used only by find and not by other commands?

2
  • 2
    Yes -exec is an option specific to find and it is used to run other commands on the results returned from the find
    – Inian
    Aug 20, 2019 at 5:59
  • 2
    BTW, you probably want find . \( -iname '*.c' -o -name '*.h' -o -name '*.l' \) -exec grep -in test1 /dev/null {} + or find . -name '*.[cChl]' -exec grep -in test1 /dev/null {} + Aug 20, 2019 at 6:02

2 Answers 2

2

Best to learn about a command is to read its manual info ls/info find or man ls/man find. Or the POSIX specification of each to learn about the subset that should be common to all different implementations.

The syntax for find is

find [options] <file1> [<file2>...] [predicates]

(some find implementations allow skipping <file1>)

And ls:

ls [options] [<file1> [<file2>...]]

(where [...] denote optional parts).

Standard options are single letter and are introduced with -. Some take arguments, some don't. Options can be combined in a single argument. For instance ls -l -d can be written ls -ld.

So you can see -exec could never be an option, because find would interpret it as -e -x -e -c (or possibly -e -x ec if the -x option was taking arguments).

Some tool implementations support long options, but those are prefixed with -- instead of - to avoid that conflict. For instance, GNU find and GNU ls both support the --help option.

For find, -exec is what POSIX calls a predicate. It is not an option. It is part of the expression that comes after the list of files and is used to determine which files are selected and what to do on them.

find also supports a few options (that come before the list of files) like -L/-H that affect its behaviour globally.

ls has no concept of predicate nor expression used to select files. Its behaviour is only affected by the options. There's no option that will let ls execute arbitrary commands.

There are a few problems with your code by the way:

  • -a (implied when omitted) has precedence over -o, so your -exec would only be run for *.l files. See `find` with multiple `-name` and `-exec` executes only the last matches of `-name`
  • you used -r for grep. That's a non standard option supported by some grep implementations to do find's job and find files inside directories. Though probably harmless here if none of the files found by find are of type directory, it's probably not wanted.
  • with the {} \; syntax, you're running one grep per file. That's very inefficient and that also means grep won't display the name of the files (unless -r above kicks in)
  • note that -iname is a non-standard extension (you may find it in info find on your system if it's a GNU one, but you won't find it at the POSIX specification).
  • as you're not using the -type predicate, find will report any type of file, not just regular ones. That could include directories, devices, fifos... Using -type f would restrict the search to regular files. With GNU find, you can also use -xtype f to select files that end up being regular after symlink resolution.

To address those, you could do:

find . -name '*.[cChl]' -type f -exec grep -in test1 /dev/null {} +
0

As the man(ual) page of find describes, and the man page of ls exactly does not, -exec is a parameter specific to find. This is why -exec works with find, but not with ls.

The man page of find says:

   -exec command ;
          Execute command; true if 0 status is returned.  All following arguments to find are taken to be arguments to the command until an argument consisting of `;' is encountered.  The string `{}' is
          replaced  by  the  current  file name being processed everywhere it occurs in the arguments to the command, not just in arguments where it is alone, as in some versions of find.  Both of these
          constructions might need to be escaped (with a `\') or quoted to protect them from expansion by the shell.  See the EXAMPLES section for examples of the use of the -exec option.  The specified
          command is run once for each matched file.  The command is executed in the starting directory.   There are unavoidable security problems surrounding use of the -exec action; you should use the
          -execdir option instead.

   -exec command {} +
          This variant of the -exec action runs the specified command on the selected files, but the command line is built by appending each selected file name at the end; the total  number  of  invoca‐
          tions  of the command will be much less than the number of matched files.  The command line is built in much the same way that xargs builds its command lines.  Only one instance of `{}' is al‐
          lowed within the command.  The command is executed in the starting directory.  If find encounters an error, this can sometimes cause an immediate exit, so some pending commands may not be  run
          at all.  This variant of -exec always returns true.

   -execdir command ;

   -execdir command {} +
          Like  -exec,  but the specified command is run from the subdirectory containing the matched file, which is not normally the directory in which you started find.  This a much more secure method
          for invoking commands, as it avoids race conditions during resolution of the paths to the matched files.  As with the -exec action, the `+' form of  -execdir  will  build  a  command  line  to
          process more than one matched file, but any given invocation of command will only list files that exist in the same subdirectory.  If you use this option, you must ensure that your $PATH envi‐
          ronment variable does not reference `.'; otherwise, an attacker can run any commands they like by leaving an appropriately-named file in a directory in which you will run -execdir.   The  same
          applies to having entries in $PATH which are empty or which are not absolute directory names.  If find encounters an error, this can sometimes cause an immediate exit, so some pending commands
          may not be run at all. The result of the action depends on whether the + or the ; variant is being used; -execdir command {} + always returns true, while -execdir command  {}  ;  returns  true
          only if command returns 0.

The ls command does not accept such a parameter.

Not the answer you're looking for? Browse other questions tagged or ask your own question.