6

I can define a function like:

myfunction () { ls -R "$1" ; }

And then

myfunction .

just works.

But if I do

echo "myfunction ." | sh
echo "myfunction ." | bash

the messages are:

sh: myfunction: not found  
bash: line 1: myfunction: command not found

Why? And how can I call a function that comes from a string if not by piping it to sh or bash?

I know there is this command source, but I am confused of when I should use source and when sh or bash. Also, I cannot pipe through source. To add to confusion, there is this command . that seems to have nothing to do with the "." that means "current directory".

3 Answers 3

10

Instead of using eval, you can export your function so it is inherited by subshells:

myfunction () { ls -R "$1" ; }
export -f myfunction

And then

echo "myfunction ." | bash

just works.

echo "myfunction ." | sh probably won't still, unless your /bin/sh is a symlink to bash.

1
  • Only works in bash, but thanks anyways
    – smac89
    Jan 10, 2021 at 23:40
8

A function definition only has an effect in the current instance of bash. When you write

echo "myfunction ." | bash

you run another instance of bash. You would need to define the function in that other instance.

If you have a string that contains a function name and arguments (quoted, if necessary), or more generally any string that contains some shell source code that you want to execute, use the eval builtin.

my_snippet='myfunction .'
eval "$my_snippet"

If you define functions in your .bashrc, they are only available in interactive shells, not in scripts.

The . command is (almost) equivalent to source, and has nothing to do with . meaning the current directory.

1

bash and sh expect their argument to be an executable file, not a string.

You can execute the contents of a string with

eval "myfunction ."

When you run a program through the shell, it will normally invoke a new instance of bash (or sh, csh, zsh, etc. as appropriate), inherit all the original shell's settings, and run itself in the new shell. This allows you to temporarily set variables or change settings without interfering with your environment.

sourceing a command will make it run it your current shell, so any changes it makes to the environment will persist when the command exits. . is a synonym for source.

In most circumstances, a script will specify what shell it is meant to run in (with #!/bin/bash in its first line, for example), and it isn't necessary for you to call bash explicitly.

2
  • A command like echo "myfunction ." | bash is not passing myfunction . to bash as a command-line argument. It's running bash and piping it the text myfunction . in lieu of standard input. That's totally different. Jun 4, 2012 at 0:30
  • You're completely right. Thanks for the reminder.
    – pconley
    Jun 4, 2012 at 4:41

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .