Question

I have the following alias in my .aliases:

alias gi grep -i

and I want to look for foo case-insensitively in all the files that have the string bar in their name:

find -name \*bar\* | xargs gi foo

This is what I get:

xargs: gi: No such file or directory

Is there any way to use aliases in xargs, or do I have to use the full version:

   find -name \*bar\* | xargs grep -i foo

Note: This is a simple example. Besides gi I have some pretty complicated aliases that I can't expand manually so easily.

Edit: I used tcsh, so please specify if an answer is shell-specific.

Was it helpful?

Solution

Aliases are shell-specific - in this case, most likely bash-specific. To execute an alias, you need to execute bash, but aliases are only loaded for interactive shells (more precisely, .bashrc will only be read for an interactive shell).

bash -i runs an interactive shell (and sources .bashrc). bash -c cmd runs cmd.

Put them together: bash -ic cmd runs cmd in an interactive shell, where cmd can be a bash function/alias defined in your .bashrc.

find -name \*bar\* | xargs bash -ic gi foo

should do what you want.

Edit: I see you've tagged the question as "tcsh", so the bash-specific solution is not applicable. With tcsh, you dont need the -i, as it appears to read .tcshrc unless you give -f.

Try this:

find -name \*bar\* | xargs tcsh -c gi foo

It worked for my basic testing.

OTHER TIPS

Turn "gi" into a script instead

eg, in /home/$USER/bin/gi:

#!/bin/sh
exec /bin/grep -i "$@"

don't forget to mark the file executable.

The suggestion here is to avoid xargs and use a "while read" loop instead of xargs:

find -name \*bar\* | while read file; do gi foo "$file"; done

See the accepted answer in the link above for refinements to deal with spaces or newlines in filenames.

This is special-character safe:

find . -print0 | xargs -0 bash -ic 'echo gi foo "$@"' --

The -print0 and -0 use \0 or NUL-terminated strings so you don't get weird things happening when filenames have spaces in them.

bash sets the first argument after the command string as $0, so we pass it a dummy argument (--) so that the first file listed by find doesn't get consumed by $0.

For tcsh (which does not have functions), you could use:

gi foo `find -name "*bar*"`

For bash/ksh/sh, you can create a function in the shell.

   function foobar 
   {
      gi $1 `find . -type f -name "*"$2"*"`
   }

   foobar foo bar

Remember that using backquotes in the shell is more advantageous than using xargs from multiple perspectives. Place the function in your .bashrc.

Using Bash you may also specify the number of args being passed to your alias (or function) like so:

alias myFuncOrAlias='echo'  # alias defined in your ~/.bashrc, ~/.profile, ...
echo arg1 arg2 | xargs -n 1 bash -cil 'myFuncOrAlias "$1"' arg0

(should work for tcsh in a similar way)

# alias definition in ~/.tcshrc
echo arg1 arg2 | xargs -n 1 tcsh -cim 'myFuncOrAlias "$1"' arg0  # untested

The simplest solution in you case would be to expand your alias inline. But that is valid for csh/tcsh only.

find -name \*bar\* | xargs `alias gi` foo

for bash it will be more tricky, not so handy but still might be useful:

find -name \*bar\* | xargs `alias gi | cut -d "'" -f2` foo
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top