Wednesday, July 30, 2008

Shell Complex Commands - Part I

find -

-exec COMMAND \;

Carries out COMMAND on each file that find matches. The command sequence terminates with ; (the ";" is escaped to make certain the shell passes it to find literally, without interpreting it as a special character).

If COMMAND contains {}, then find substitutes the full path name of the selected file for "{}".

- find ~/ -name 'core*' -exec rm {} \;
# Removes all core dump files from user's home directory.

find ~/ -maxdepth 1 -name '*.sh' -exec ls -al {} \;
-rw-r--r-- 1 testuser dummy 1168 2008-07-24 21:08 /home/testuser/log_cleanup.sh
-rw-r--r-- 1 testuser dummy 17 2008-07-30 18:45 /home/testuser/test1.sh

xargs
A filter for feeding arguments to a command, and also a tool for assembling the commands themselves. It breaks a data stream into small enough chunks for filters and commands to process. Consider it as a powerful replacement for backquotes. In situations where command substitution fails with a too many arguments error, substituting xargs often works.

Normally, xargs reads from stdin or from a pipe, but it can also be given the output of a file.

The default command for xargs is echo. This means that input piped to xargs may have linefeeds and other whitespace characters stripped out.

every file in current directory, one at a time, prompting before each operation.
ls | xargs -p -l gzip gzips

Grep for linux in mails. find ~/mail/ -type f | xargs grep "Linux

Copying files in current directory to another,

#!/bin/bash
# copydir.sh
# Copy (verbose) all files in current directory ($PWD) to directory specified on command line.

E_NOARGS=65
if [ -z "$1" ] # Exit if no argument given.
then
echo "Usage: `basename $0` directory-to-copy-to"
exit $E_NOARGS
fi
ls . | xargs -i -t cp ./{} $1
# ^^ ^^ ^^
# -t is "verbose" (output command line to stderr) option.
# -i is "replace strings" option.
# {} is a placeholder for output text.
# This is similar to the use of a curly bracket pair in "find."
#
# List the files in current directory (ls .),
#+ pass the output of "ls" as arguments to "xargs" (-i -t options),
#+ then copy (cp) these arguments ({}) to new directory ($1).
#
# The net result is the exact equivalent of
#+ cp * $1
#+ unless any of the filenames has embedded "whitespace" characters.

Xargs EXIT STATUS
xargs exits with the following status:
0 if it succeeds
123 if any invocation of the command exited with status 1-125
124 if the command exited with status 255
125 if the command is killed by a signal
126 if the command cannot be run
127 if the command is not found
1 if some other error occurred.

find /tmp -name core -type f -print | xargs /bin/rm -f
Find files named core in or below the directory /tmp and delete them. Note that this will work incorrectly if there are any filenames containing newlines or spaces.

find /tmp -name core -type f -print0 | xargs -0 /bin/rm -f
Find files named core in or below the directory /tmp and delete them, processing filenames in such a way that file or directory names containing spaces or newlines are correctly handled.

ps aux | grep "/sbin/klogd" | grep -v grep | awk '{ print $2}' | xargs -I kill {}
This will kill process klogd. Useful when you want to kill process by there name.

No comments: