Reputation: 3994
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.
Upvotes: 3
Views: 2364
Reputation: 8406
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
Upvotes: 1
Reputation: 2362
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.
Upvotes: 2
Reputation: 1220
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
Upvotes: 4
Reputation: 361595
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"
Upvotes: 1