I tested this:

~$ test() { echo foo |sed -r s/.*(.)/\\1/g; }
~$ test

So far so good. But then:

~$ export -f test
~$ bash -c ''
bash: test: line 0: syntax error near unexpected token `('
bash: test: line 0: `test () {  echo foo | sed -r s/.*(.)/\\1/g'
bash: error importing function definition for `test'

I know using quotes with sed solves the problem. But bash not exporting a function that runs is alarming and requires explanations, rules and cases.

I would expect bash to be able to handle its own quoting, so I think it can only be a bug.

  • 1
    Possible duplicate of What does env x='() { :;}; command' bash do and why is it insecure? – Inian Feb 8 '18 at 9:20
  • 1
    This is not a duplicate. I don't see any relation to the linked question other than the fact that this question is using an exported function, which is a fully supported bash feature. – Patrick Feb 8 '18 at 13:59
  • @Inian I did the testing suggested there. My system fully passed the test; it's patched. I guess you can (vote to) remove the "This question may already have an answer here" box now. – argle Feb 8 '18 at 14:48

I suspect you have 2 versions of bash on your system, and that when you're calling bash -c '', you're invoking a different version. That or your code was altered when you created the question.

As for why I think this, your code does not work on my system:

$ test() { echo foo |sed -r s/.*(.)/\\1/g; }
bash: syntax error near unexpected token `('

The issue is that you have no quotes around the sed expression, so bash is trying to interpret it as a shell expression. I'm guessing this behavior changed between bash versions, and that your login shell is a different version of bash than whatever is in your $PATH when calling bash -c ''.
You can check this by doing:

$ echo $SHELL
$ which bash


Another possible cause would be if you have some shell options set which are changing the behavior of bash's expression evaluation, and these options are not being used by the bash -c ''.


As for how to fix the issue, when I properly quote the sed expression, it works fine:

$ test() { echo foo | sed 's/.*\(.\)/\1/g'; }
$ export -f test
$ bash -c 'test'

(Note: I had to slighly tweak the sed command as it's not a valid command for my version of sed)

| improve this answer | |
  • Not versions, but indeed --norc makes the difference. – argle Feb 8 '18 at 14:22
  • Please run . /usr/share/bash-completion/bash_completion || . /etc/bash_completion first and tell me if you get the same behavior. This is the culprit, in my .bashrc. I am also curious if you have an explanation. – argle Feb 8 '18 at 21:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.