summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Youngman <jay@gnu.org>2008-02-09 10:58:20 +0000
committerJames Youngman <jay@gnu.org>2008-02-09 10:58:20 +0000
commitca9d2f5d004ed825149fe5d48cc18ad31048e41c (patch)
tree778bb10071be6da72fb2b797b677f710775456cd
parentdec6d89d6e5cee4696244239c2ccbd8cca03116e (diff)
downloadfindutils-ca9d2f5d004ed825149fe5d48cc18ad31048e41c.tar.gz
Better documentation for the use of 'sh -c' from xargs
-rw-r--r--ChangeLog9
-rw-r--r--NEWS5
-rw-r--r--doc/find.texi118
-rw-r--r--xargs/xargs.14
4 files changed, 133 insertions, 3 deletions
diff --git a/ChangeLog b/ChangeLog
index 59c8f92f..6590c08e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,14 @@
2008-02-09 James Youngman <jay@gnu.org>
+ * doc/find.texi (xargs options): Moved documentation of xargs'
+ options into this new section.
+ (Invoking the shell from xargs): New section providing examples
+ about "xargs sh -c '...'".
+
+ * xargs/xargs.1: Indicate that the "sh -c" trick with xargs
+ achieves the same thing as BSD's "xargs -o", but in a more
+ flexible way.
+
* locate/updatedb.sh: Actually rename the old database to the new
one atomically, instead of just claiming the rename is atomic in a
comment :) This fixes Savannah bug #22057.
diff --git a/NEWS b/NEWS
index e6c6fbee..d947f648 100644
--- a/NEWS
+++ b/NEWS
@@ -12,6 +12,11 @@ comment.
the total count of unreaped children has not yet reached the maximum
allowed.
+** Documentation Fixes
+
+Documented various useful techniques with invoking "sh -c" from
+xargs in the Texinfo documentation.
+
* Major changes in release 4.3.12, 2007-12-19
** Bug Fixes
diff --git a/doc/find.texi b/doc/find.texi
index 6ef60ad2..dd14f1e6 100644
--- a/doc/find.texi
+++ b/doc/find.texi
@@ -3400,7 +3400,16 @@ if some other error occurred.
Exit codes greater than 128 are used by the shell to indicate that
a program died due to a fatal signal.
-
+
+
+@menu
+* xargs options::
+* Invoking the shell from xargs::
+@end menu
+
+@node xargs options
+@subsection xargs options
+
@table @code
@item --arg-file@r{=@var{inputfile}}
@itemx -a @r{@var{inputfile}}
@@ -3520,6 +3529,95 @@ Run simultaneously up to @var{max-procs} processes at once; the default is 1. I
possible simultaneously.
@end table
+@node Invoking the shell from xargs
+@subsection Invoking the shell from xargs
+
+Normally, @code{xargs} will exec the command you specified directly,
+without invoking a shell. This is normally the behaviour one would
+want. It's somewhat more efficient and avoids problems with shell
+metacharacters, for example. However, sometimes it is necessary to
+manipulate the environment of a command before it is run, in a way
+that @code{xargs} does not directly support.
+
+Invoking a shell from @code{xargs} is a good way of performing such
+manipulations. However, some care must be taken to prevent problems,
+for example unwanted interpretation of shell metacharacters.
+
+This command moves a set of files into an archive directory:
+
+@example
+find /foo -maxdepth 1 -atime +366 -exec mv @{@} /archive \;
+@end example
+
+However, this will only move one file at a time. We cannot in this
+case use @code{-exec ... +} because the matched file names are added
+at the end of the command line, while the destination directory would
+need to be specified last. We also can't use @code{xargs} in the
+obvious way for the same reason. One way of working around this
+problem is to make use of the special properties of GNU @code{mv}; it
+has a @code{-t} option that allows the target directory to be
+specified before the list of files to be moved. However, while this
+technique works for GNU @code{mv}, it doesn't solve the more general
+problem.
+
+Here is a more general technique for solving this problem:
+
+@example
+find /foo -maxdepth 1 -atime +366 -print0 |
+xargs -r0 sh -c 'mv "$@@" /archive' move
+@end example
+
+Here, a shell is being invoked. There are two shell instances to
+think about. The first is the shell which launches the xargs command
+(this might be the shell into which you are typing, for example). The
+second is the shell launched by @code{xargs} (in fact it will probably
+launch several, one after the other, depending on how many files need
+to be archived). We'l refer to this second shell as a subshell.
+
+Our example uses the @code{-c} option of @code{sh}. Its argument is a
+shell command to be executed by the subshell. Along with the rest of
+that command, the $@@ is enclosed by single quotes to make sure it is
+passed to the subshell without being expanded by the parent shell. It
+is also enclosed with double quotes so that the subshell will expand
+@code{$@@} correctly even if one of the file names contains a space or
+newline.
+
+The subshell will use any non-option arguments as positional
+parameters (that is, in the expansion of @code{$@@}). Because
+@code{xargs} launches the @code{sh -c} subshell with a list of files,
+those files will end up as the expansion of @code{$@@}.
+
+You may also notice the @samp{move} at the end of the command line.
+This is used as the value of @code{$0} by the subshell. We include it
+because otherwise the name of the first file to be moved would be used
+instead. If that happened it would not be included in the subshell's
+expansion of @code{$@@}, and so it wouldn't actually get moved.
+
+
+Another reason to use the @code{sh -c} construct could be to
+perform redirection:
+
+@example
+find /usr/include -name '*.h' | xargs grep -wl mode_t |
+xargs -r sh -c 'exec emacs "$@@" < /dev/tty' Emacs
+@end example
+
+Notice that we use the shell builtin @code{exec} here. That's simply
+because the subshell needs to do nothing once Emacs has been invoked.
+Therefore instead of keeping a @code{sh} process around for no reason,
+we just arrange for the subshell to exec Emacs, saving an extra
+process creation.
+
+Sometimes, though, it can be helpful to keep the shell process around:
+
+@example
+find /foo -maxdepth 1 -atime +366 -print0 |
+xargs -r0 sh -c 'mv "$@@" /archive || exit 255' move
+@end example
+
+Here, the shell will exit with status 255 if any @code{mv} failed.
+This causes @code{xargs} to stop immediately.
+
@node Regular Expressions
@section Regular Expressions
@@ -3641,7 +3739,23 @@ xargs --arg-file=todo emacs
@end example
Here, @code{xargs} will run @code{emacs} as many times as necessary to
-visit all of the files listed in the file @file{todo}.
+visit all of the files listed in the file @file{todo}. Generating a
+temporary file is not always convenient, though. This command does
+much the same thing without needing one:
+
+@example
+find /usr/include -name '*.h' | xargs grep -l mode_t |
+xargs sh -c 'emacs "$@@" < /dev/tty' Emacs
+@end example
+
+The example above illustrates a useful trick; Using @code{sh -c} you
+can invoke a shell command from @code{xargs}. The @code{$@@} in the
+command line is expanded by the shell to a list of arguments as
+provided by @code{xargs}. The single quotes in the command line
+protect the @code{$@@} against expansion by your interactive shell
+(which will normally have no arguments and thus expand @code{$@@} to
+nothing). The capitalised @samp{Emacs} on the command line is used as
+@code{$0} by the shell that @code{xargs} launches.
@node Archiving
@section Archiving
diff --git a/xargs/xargs.1 b/xargs/xargs.1
index ffa224f6..6910f465 100644
--- a/xargs/xargs.1
+++ b/xargs/xargs.1
@@ -356,7 +356,9 @@ Generates a compact listing of all the users on the system.
Launches the minumum number of copes of Emacs needed, one after the
other, to edit the files listed on
.BR xargs '
-standard input.
+standard input. This example achieves the same effect as BSD's
+.B -o
+option, but in a more flexible and portable way.