Executing for-each in bash
I'm looking to write a Bash one-liner that calls a function once for each item in a list. For example, given the list
foo bar bazand the pr开发者_如何转开发ogram "cowsay", it would produce:
_____
< foo >
-----
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
_____
< bar >
-----
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
_____
< baz >
-----
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
(Maybe with additional text in between, doesn't really matter)
I know I can do this with a bash script:
#!/bin/sh
for w in $@; do
cowsay $w
done
But I can't imagine that there isn't another way to do it.
EDIT: I wasn't very clear in my initial question, I think. I want to be able to do something like this without writing a bash script:
locate foo | sed s/bar/baz/ | [other-processing] | [insert-magic-here] cowsay
The point is that I'm trying to avoid having to write a script, so that I can just add it to my pipe chain and not think about it.
Sounds like you want to use xargs then.
$ echo foo bar | xargs -n 1 cowsay
_____
< foo >
-----
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
_____
< bar >
-----
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
You want xargs
. Without a for
, while
, or until
loop structure, xargs
is about the only thing that will do what you ask.
Use -n1
if you need xargs to execute your command for each input, instead of executing with many inputs as separate arguments. Your example becomes:
$ locate foo | sed s/bar/baz/ | [other-processing] | xargs -n1 cowsay
In one line:
for i in foo bar baz; do cowsay $i; done
Or more clearly:
foobar="foo bar baz"
for i in $foobar
do
cowsay $i
done
As other's have said, xargs(1) is what you want, but it is not always suitable. Most often when it has failed for me, it was when I wanted to run a shell function. xargs runs an executable command.
You can put a loop in your pipeline without needing to put it in a shell script:
$ locate foo | sed s/bar/baz/ | [other-processing] | while read line ; do cowsay "$line" ; done
If cowsay was a shell function, this pipeline would work, but not with xargs.
You could write a function that turns this into a liner:
function foreach
{
func=$1; shift
for arg in $@; do
${func} ${arg}
done
}
And then invoke it like:
foreach cosway foo bar baz
If you are not interested in using a "for" loop, then your other options to iterate over a list of strings is to use a "while" or "until" loop.
Is it the case that you are wanting to write a bash script that can be executed as follows?
$ cowsay-loop foo bar buzz
精彩评论