开发者

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 baz
and 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

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜