71

I'm trying to run the following command:

find . -iname '.#*' -print0 | xargs -0 -L 1 foobar

where "foobar" is an alias or function defined in my .bashrc file (in my case, it's a function that takes one parameter). Apparently xargs doesn't recognize these as things it can run. Is there a clever way to remedy this?

Ian Greenleaf Young
  • 1,888
  • 2
  • 15
  • 23
  • 2
    This is one of the reasons why I create scripts on my ~/bin folder instead of creating bash aliases. This way, I can use my aliases from any shell: BASH, ZSH, IPYTHON or FISH. – Yoo Sep 13 '09 at 12:34
  • 2
    Here's a similar (though not identical) question: http://stackoverflow.com/questions/979453/how-can-i-use-aliased-commands-with-xargs – Nathan Fellman Mar 08 '10 at 12:07

6 Answers6

41

Since only your interactive shell knows about aliases, why not just run the alias without forking out through xargs?

find . -iname '.#*' -print0 | while read -r -d '' i; do foobar "$i"; done

If you're sure that your filenames don't have newlines in them (ick, why would they?), you can simplify this to

find . -iname '.#*' -print | while read -r i; do foobar "$i"; done

or even just find -iname '.#*' | ..., since the default directory is . and the default action is -print.

One more alternative:

 IFS=$'\n'; for i in `find -iname '.#*'`; do foobar "$i"; done

telling Bash that words are only split on newlines (default: IFS=$' \t\n'). You should be careful with this, though; some scripts don't cope well with a changed $IFS.

ephemient
  • 198,619
  • 38
  • 280
  • 391
  • 4
    This answer is answering WHY we can't use xargs and HOW we could use xargs with the alias. – Ivailo Bardarov Nov 24 '11 at 10:35
  • 4
    This answer gives us *alternatives* to using xargs. For an answer that works *using xargs*, see @camh's answer in the related question: http://stackoverflow.com/questions/979453/how-can-i-use-aliased-commands-with-xargs (which Nathan Fellman linked to up above) – Noach Magedman Jan 16 '13 at 16:59
  • xargs can use paralell mode, so that while is not suitable – whi Feb 16 '22 at 10:42
  • The default path of `find` is `.` for GNU find but not for BSD find ([FreeBSD](https://www.freebsd.org/cgi/man.cgi?find(1)), [OpenBSD](https://man.openbsd.org/find.1), [NetBSD](https://man.netbsd.org/find.1), [macOS](https://keith.github.io/xcode-man-pages/find.1.html)), which are conform to [POSIX](https://pubs.opengroup.org/onlinepubs/9699919799/utilities/find.html) in that respect. – Stefan Schmidt Oct 20 '22 at 17:15
12

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
echo arg1 arg2 | xargs  bash -cil 'myFuncOrAlias "$@"' arg0
tilo
  • 129
  • 1
  • 2
12

Adding a trailing space to the command being aliased causes other aliased commands to expand:

alias xargs='xargs ' # aliased commands passed to xargs will be expanded

See this answer for more info:
https://stackoverflow.com/a/59842439/11873710

ken hicks
  • 321
  • 3
  • 3
6

This doesn't work because xargs expects to be able to exec the program given as its parameter.

Since foobar in your case is just a bash alias or function there's no program to execute.

Although it involves starting bash for each file returned by find, you could write a small shell script thus:

#!/bin/bash
. $(HOME)/.bashrc
func $*

and then pass the name of that script as the parameter to xargs

Alnitak
  • 334,560
  • 70
  • 407
  • 495
1

I usually use find like this:

find . -iname '' -exec cmd '{}' \;

'{}' will get replaced with the filename, and \; is necessary to terminate the execution chain. However, if that doesn't work with your function, you might need to run it through bash:

find .. |sed -e "s/.*/cmd '&'/"|bash

Find prints each file on a line, sed just prefixes this with your command, and then pipe it to bash for execution. Skip the |bash first to see what will happen.

Staale
  • 27,254
  • 23
  • 66
  • 85
  • If you're using a newish GNU find, use `-exec cmd '{}' +` instead: this acts more like xargs in that it will batch arguments together into one run instead of exec'ing a new cmd for every file found. – ephemient Feb 04 '09 at 22:21
  • I rather think if his function was capable of taking multiple parameters he wouldn't be supplying the -L 1 options to xargs... – Alnitak Feb 04 '09 at 22:25
  • Oh, that's what -L does? I didn't look it up, and I use -n for that purpose. – ephemient Feb 04 '09 at 22:46
  • 1
    Sadly, these methods still don't work with aliases and functions. Probably because .bashrc only gets invoked for interactive shells. But the first one IS a neat trick. – Ian Greenleaf Young Feb 07 '09 at 18:03
0

try

find . -iname '.#*' -print0 | xargs -0 -L 1 $(foobar)