Bash 4.2 on CentOS 6.5:
In my ~/.bash_profile
I have a bunch of aliases, including:
alias grep='grep -n --color=always'
so that I can get color highlighting and print line numbers automatically when running grep
. If I run the following, highlighting works as expected:
$ grep -Re 'regex_here' *.py
However, when I ran this recently:
$ find . -name '*.py' | xargs grep -E 'regex_here'
the results were not highlighted and line numbers weren't printed, forcing me to go back and explicitly add -n --color=always
to the grep
command.
- Does
xargs
not read aliases in the environment? - If not, is there a way to make it do that?
Best Answer
An alias is internal to the shell where it is defined. It is not visible to other processes. The same goes for shell functions.
xargs
is a separate application, which is not a shell, so doesn't have a concept of aliases or functions.You can make xargs invoke a shell instead of invoking
grep
directly. However just invoking a shell isn't enough, you have to define the alias in that shell as well. If the alias is defined in your.bashrc
, you can source that file; however this may not work your.bashrc
performs other tasks that don't make sense in a non-interactive shell.Beware of the intricacies of nested quoting when typing the regexp. You can simplify your life by passing the regexp as a parameter to the shell.
You can perform the alias lookup explicitly. Then
xargs
will seegrep -n --color=always
.In zsh:
By the way, note that
find … | xargs …
breaks on filenames containing spaces (among others). You can fix this by changing to null-delimited records:or by using
-exec
:Instead of calling
find
, you can do everything entirely inside the shell. The glob pattern**/
traverses directories recursively. In bash, you need to runshopt -s globstar
to enable this glob pattern first.This has a few limitations:
**/
recurses into symbolic links to directories.Another approach is to use process substitution, as suggested by MariusMatutiae.
This is useful when
**/
isn't applicable: for complexfind
expressions, or in bash ≤4.2 when you don't want to recurse under symbolic links. Note that this breaks on file names containing spaces; a workaround is to setIFS
and disable globbing, but it's starting to get a bit complex: