4

I have already searched about this particular problem, but couldn't find anything helpful.

Let's assume I have following functions defined in my ~/.bashrc (Note: this is pseudo-code!):

ANDROID_PLATFORM_ROOT="/home/simao/xos/src/"

function getPlatformPath() {
  echo "$ANDROID_PLATFORM_ROOT"
}

function addCaf() {
  # Me doing stuff
  echo "blah/$(getPlatformPath)"
}

function addAosp() {
  # Me doing stuff
  echo "aosp/$(getPlatformPath)"
}

function addXos() {
  # Me doing stuff
  echo "xos/$(getPlatformPath)"
}

function addAllAll() {
  cd $(gettop)
  # repo forall -c "addCaf; addAosp; addXos" # Does not work!
  repo forall -c # Here is where I need all those commands
}

My problem:

I need to get the functions addCaf, addAosp and addXos in one single line.

Like you can run following in bash (pseudo code):

dothis; dothat; doanotherthing; trythis && succeedsdothis || nosuccessdothis; blah

I would like to run all commands inside the three functions addCaf, addAosp and addXos in just one line.

Any help is appreciated.

What I already tried:

repo forall -c "bash -c \"source ~/.bashrc; addAllAll\""

But that didn't work as well.

Edit:

To clarify what I mean.

I want something like that as a result:

repo forall -c 'function getPlatformPath() { echo "$ANDROID_PLATFORM_ROOT"; }; ANDROID_PLATFORM_ROOT="/home/simao/xos/src/"; echo "blah/$(getPlatformPath)"; echo "aosp/$(getPlatformPath)"; echo "xos/$(getPlatformPath)"'

But I don't want to write that manually. Instead, I want to get those lines from the functions that already exist.

6
  • Not sure what you are asking, but if you want to create a function on one line, you can use function f() { echo hi; }. Note the final ;. Commented Aug 3, 2016 at 11:46
  • Well, I want to get the content of a function in one line in one string. Commented Aug 3, 2016 at 12:11
  • Why do you need the content of the functions instead of just running the functions themselves? Because you need to embed the calls in the argument to repo (whatever that is)? Does type addXos do (most of) what you need? Or actually declare -f addXos? Commented Aug 3, 2016 at 12:23
  • Because, for whatever reason, the repo tool does not accept that. I could be writing the stuff into the quotes but I am lazy :P Commented Aug 3, 2016 at 12:37
  • From your question, it's unclear what repo all -c does with the next positional argument. Does it run shell substitution on it (like bash -c), or does it interpret it as a command? The last 2 code snippets suggest different things. Commented Aug 3, 2016 at 14:35

5 Answers 5

6

You can use type and then parse its output to do whatever you want to do with the code lines.

$ foo() {
> echo foo
> }

$ type foo
foo is a function
foo () 
{ 
    echo foo
}

Perhaps this example makes things more clear:

#!/bin/bash

foo() {
    echo "foo"
}

bar() {
    echo "bar"
}

export IFS=$'\n'

for f in foo bar; do
    for i in $(type $f | head -n-1 | tail -n+4); do
        eval $i
    done
done

exit 0

This is how it looks:

$ ./funcs.sh 
foo
bar

What the script is doing is first loop over all the functions you have (in this case only foo and bar). For each function, it loops over the code of that function (skipping the useless lines from type's output) and it executes them. So at the end it's the same as having this code...

echo "foo"
echo "bar"

...which are exactly the code lines inside the functions, and you are executing them one after the other.

Note that you could also build a string variable containing all the code lines separated by ; if instead of running eval on every line you do something like this:

code_lines=

for f in foo bar; do
        for i in $(type $f | head -n-1 | tail -n+4); do
                if [ -z $code_lines ]; then
                        code_lines="$i"
                else
                        code_lines="${code_lines}; $i"
                fi  
        done
done

eval $code_lines
Sign up to request clarification or add additional context in comments.

1 Comment

That's almost what I need. Can you also tell me how I can remove foo is a function and foo() { }, only keeping the lines themselves in one single line like this: echo foo; echo foo2; echo foo3;..., assuming that those commands are in that particular function?
2

Assuming that repo forall -c interprets the next positional argument just as bash -c, try:

foo () { 
    echo "foo!"
}
boo () { 
    if true; then
        echo "boo!"
    fi
}
echo works | bash -c "source "<(typeset -f foo boo)"; foo; boo; cat"

Note:

  • The difference from the original version is that this no longer interferes with stdin.

  • The <(...) substitution is unescaped because it must be performed by the original shell, the one where foo and boo are first defined. Its output will be a string of the form /dev/fd/63, which is a file descriptor that is passed open to the second shell, and which contains the forwarded definitions.

Comments

1

Make a dummy function foo(), which just prints "bar":

foo() { echo bar ; }

Now a bash function to print what's in one (or more) functions. Since the contents of a function are indented with 4 spaces, sed removes any lines without 4 leading spaces, then removes the leading spaces as well, and adds a ';' at the end of each function:

# Usage: in_func <function_name1> [ ...<function_name2> ... ]
in_func() 
    { while [ "$1" ] ; do \
          type $1 | sed  -n '/^    /{s/^    //p}' | sed '$s/.*/&;/' ; shift ; \
      done ; }

Print what's in foo():

in_func foo

Output:

echo bar;

Assign what's in foo() to the string $baz, then print $baz:

baz="`in_func foo`" ; echo $baz

Output:

echo bar;

Run what's in foo():

eval "$baz"

Output:

bar

Assign what's in foo() to $baz three times, and run it:

baz="`in_func foo foo foo`" ; eval "$baz"

Output:

bar
bar
bar

5 Comments

Caveat: some folks regard most any language's form of eval as eeville, not entirely without reason.
This works. Just copy&pasted that in_func function, then just ran the following: repo forall -c "$(in_func addAosp) $(in_func addXos) $(in_func addCaf). But it is a bit buggy with the repo tool. Well, this answer is the correct one.
Removing spacing and adding ;-s won't work with higher bash constructs such as while, for, if. E.g.: boo () { while false; do echo bar; done; echo ok; }; eval $(in_func boo) gives a syntax error. (The problem is that in_func adds a ; right after do.) My answer somewhere below is not limited in this way, but alas this was accepted.
@MateiDavid, thanks for the bug report. I should have tried in_func in_func, since it too contains a while. Have now added a do check to the answer sed code.
Revised do correction -- just stick a ; on the end only. Should fix the problems MateiDavid pointed out. (Couldn't figure out how to do it without invoking sed twice.)
1

Shell functions aren't visible to child processes unless they're exported. Perhaps that is the missing ingredient.

export -f addCaf addAosp addXos
repo forall -c "addCaf; addAosp; addXos"

1 Comment

Even though your answer might be correct, I am facing following error message: Got an error, terminating the pool: OSError: [Errno 2] No such file or directory. Seems to be related to the repo tool. Anyways, this does not help me in this particular situation. Do you know how I can echo the content of a function, means all single commands?
0

This should work:

repo forall -c "$(addCaf) $(addAosp) $(addXos)"

2 Comments

I don't want the result of the functions, I want the content.
No problem, nice suggestion though.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.