magguu
magguu

Reputation: 105

Changing the defintion of shell builtins (eg echo) for all subsequent invocations but only within the scope of current shell

I have a shell script (say test.sh) which calls more shell scripts (not written by me). These other shell scripts (say test2.sh and test3.sh) are complicated which I do not want to edit (for reasons of not messing as well as keeping the option of update alive)

test2.sh and test3.sh has several calls to various shell builtins (eg echo). I want to change the definition of (example) echo in test.sh so that whenever test2.sh is called, I get a modified echo of the type

echo [test2] blah blah

Then before invoking test3.sh I want to alter echo once again so that all the echo's of test3.sh work as-

echo [test3] blah blah

I have tried doing that with alias, export, function etc. none of which works as desired. I am including my examples below -

file :: test.sh

#!/bin/bash

#alias echo='function __echo(){ /bin/echo [DB] $* ; unset -f __echo;}; __echo  ' # does not work
echo()  { /bin/echo [test2] $* ; }; # works only within test.sh. test2.sh does not see this function. exporting does not help.
echo "blah" "blah"; # echoes [test2] blah blah
./test2.sh "one more arg" "second arg";
echo()  { /bin/echo [test3] $* ; }; # no luck once again
./test3.sh "test3 arg1" "test3 arg2";

file :: test2.sh

#!/bin/bash
/bin/echo "First arg = \"$1\""; # no problem here
/bin/echo "Secnd arg = \"$2\"";
echo $1 # behaves as the usual echo
echo $2
echo $*

Any ideas how to do it? If possible not just for echo but for other utilities too.

Upvotes: 0

Views: 61

Answers (2)

magguu
magguu

Reputation: 105

Though @ruakh's suggested modification of my original approach works well, it messes with other things. If test2.sh or test3.sh have redirected echos then none of those redirected echos will work properly. I want only those lines directed to stdout to be affected.

Since then I have found a new solution, which admittedly is somewhat cumbersome.

file :: test.sh

#!/bin/bash
echo "blah blah"; # no change here
y=`./test2.sh "arg 1" "arg 2" 2>/dev/null`
while read -r x
do
echo "[test2] $x";
done <<< "$y"; # correctly appends [test2] before every output of test2.sh

#similarly for `test3.sh`

now even if test2.sh contains line of the form

echo "some text" > file1;

only those lines actually coming out to stdout will be affected.

But now every invocation of test2.sh must be changed :(

Upvotes: 0

ruakh
ruakh

Reputation: 183436

You had it right with export, but since shell functions aren't just normal variables, you need to use the special -f flag:

export -f echo

I think the implementation details depend on the version of Bash, but on the one I have handy, export -f works by creating an environment variable named BASH_FUNC_the_function_name() and setting it to () { the_function_body ; }. When Bash starts up, it searches for environment variables of that form, and creates the appropriate functions. (A quirk in this functionality is what enabled the Shellshock security vulnerability.)

Upvotes: 1

Related Questions