Nathan Fellman
Nathan Fellman

Reputation: 127578

How can I use aliased commands with xargs?

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.

Upvotes: 42

Views: 13515

Answers (9)

Nagev
Nagev

Reputation: 13275

After trying many solutions with xargs that didn't work for me, went for an alternative with a loop, see examples below:

for file in $(git ls-files *.txt); do win2unix $file; done
for file in $(find . -name *.txt); do win2unix $file; done

Put your expression that generates a list of files inside $() as in the examples above. I've used win2unix which is a function in my .bashrc that takes a file path and converts it to Linux endings. Would expect aliases to also work.

Note that I did not have spaces in my paths or filenames.

Upvotes: 0

Tom Hale
Tom Hale

Reputation: 46983

This is special-character safe:

find . -print0 | xargs -0 bash -ic '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.

Upvotes: 3

ken hicks
ken hicks

Reputation: 431

This solution worked perfect for me in bash:
https://unix.stackexchange.com/a/244516/365245

Problem

[~]: alias grep='grep -i'
[~]: find -maxdepth 1 -name ".bashrc" | xargs grep name      # grep alias not expanded
[~]: ### no matches found ###

Solution

[~]: alias xargs='xargs ' # create an xargs alias with trailing space
[~]: find -maxdepth 1 -name ".bashrc" | xargs grep name     # grep alias gets expanded
# Name     : .bashrc

Why it works

[~]: man alias  
alias: alias [-p] [name[=value] ... ]  
(snip)  
A trailing space in VALUE causes the next word to be checked for
alias substitution when the alias is expanded.

Upvotes: 15

Feniks
Feniks

Reputation: 11

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

Upvotes: 1

Pete TerMaat
Pete TerMaat

Reputation: 3205

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.

Upvotes: 7

tilo
tilo

Reputation: 1

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

Upvotes: 0

Ryan Oberoi
Ryan Oberoi

Reputation: 14505

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.

Upvotes: 0

camh
camh

Reputation: 42498

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.

Upvotes: 36

Peter Ericson
Peter Ericson

Reputation: 1907

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.

Upvotes: 8

Related Questions