10

I am getting this one when I open a terminal session:

sh: error importing function definition for `read.json'

sh: error importing function definition for `ts-project'

sh doesn't like these functions because they look like:

read.json(){
   ::
}

and

ts-project(){
   ::
}

the real question is - why is sh touching/interpreting these files? I am on MacOS and seen this before, it's such a mystery. I would think only bash would be loading these files.

update: bash and sh are nothing out of the ordinary. when I type bash into the terminal, I get this:

alex$ bash
beginning to load .bashrc
finished loading .bashrc
bash-3.2$ 

when I type sh in the terminal, I get this:

alex$ sh
sh: error importing function definition for `read.json'
sh: error importing function definition for `ts-project'
sh-3.2$ 
Alexander Mills
  • 9,330
  • 19
  • 95
  • 180

3 Answers3

20

That error happens when bash masquerading as a POSIX shell tries to import those functions from the environment, not when loading them by interpreting a file like ~/.bashrc or such. Simplified example:

foo.bar(){ true; }; export -f foo.bar; bash --posix -c true
bash: error importing function definition for `foo.bar'

I was expecting bash not to load functions from the environment when in posix mode, but it does, and only complains when their names contain funny characters.

Notice that bash will also run in posix mode when the POSIXLY_CORRECT or POSIX_PEDANTIC environment variable is set, or when it was compiled with --enable-strict-posix-default / STRICT_POSIX.

This latter seems to be the case for /bin/sh on MacOS (look here for PRODUCT_NAME = sh), where I expect this error to also trigger when using library functions like popen(3) or system(3).

  • 3
    The fix: don't export functions in the environment. It's the bash anti-feature that led to (or rather, simply was) Shellshock and it should have been removed, but wasn't because people are foolishly using it. Don't be one of them. – R.. GitHub STOP HELPING ICE Aug 27 '19 at 12:14
  • The fact that bash imports functions even when called as `sh` is what made the shellshock/bashdoor vulnerability a **lot** worse. – Stéphane Chazelas Aug 27 '19 at 13:53
  • See also `SHELLOPTS=posix` and `-o posix` for other ways to enable the posix mode. – Stéphane Chazelas Aug 27 '19 at 13:59
  • Also note that `set -a` / `set -o allexport` also causes bash to export all functions (and if invoked as `sh`, causes `POSIXLY_CORRECT` to be set and exported!) – Stéphane Chazelas Aug 27 '19 at 14:04
  • (`sh -a` causes `POSIXLY_CORRECT` to be set and exported; `set -a` after `sh` without `-a` was started doesn't export `POSIXLY_CORRECT` because it was set before `-a` was in effect). – Stéphane Chazelas Aug 27 '19 at 14:13
  • @StéphaneChazelas it seems that the functions are imported _before_ `SHELLOPTS` is processed. This will complain about `baz.quux` but not about `foo.bar`: `bash -c 'foo.bar(){ echo yup; }; export -f foo.bar; set -o posix; export SHELLOPTS; bash -c "foo.bar; baz.quux(){ :; }"'`. –  Aug 27 '19 at 16:53
  • Same thing when invoking a `bash` _not_ compiled with with `-DSTRICT_POSIX` as `sh` (eg. on rhel, centos where `/bin/sh` is a regular `bash`) -- functions with funny names will be imported from the environment, but no new functions like that can be defined. All this is still the case in the latest version (5.0.9). –  Aug 27 '19 at 17:34
  • @mosvy, yes it's all about the order things are processed, it is all a bit messy. When bash is invoked as `sh`, POSIX mode ends up being set quite late. Same with `SHELLOPTS`. – Stéphane Chazelas Aug 27 '19 at 18:39
  • How can I check if POSIX mode is turned on with bash? – Alexander Mills Aug 29 '19 at 00:04
  • @AlexanderMills `case :$SHELLOPTS: in *:posix:*) ...` –  Aug 29 '19 at 00:10
5

To answer the part about why read.json and ts-project are not portable function names:

According to POSIX, a function definition must be named by

a word consisting solely of underscores, digits, and alphabetics from the portable character set. The first character of a name is not a digit.

Also known as an identifier, in C lingo. Or in regex: [_a-zA-Z][0-9_a-zA-Z]*

user2394284
  • 352
  • 1
  • 4
  • 10
  • But POSIX doesn't forbid implementations from accepting other names for functions, so bash didn't *have* to impose those restrictions when in POSIX mode. function names share the same namespace as command arguments, so there's no reason to accept just _anything_ (like `zsh`/`rc`/`fish`...) – Stéphane Chazelas Aug 27 '19 at 18:45
  • @StéphaneChazelas: I know, but what does it mean to be in POSIX mode, if not "shed all extensions", as in "not silently accept them"? – user2394284 Aug 28 '19 at 07:50
  • @user2394284 it certainly doesn't mean that in `bash`, or it would not import functions from the environment while in POSIX mode, which is not required by the POSIX spec ;-) –  Aug 28 '19 at 09:55
  • @mosvy: Yeah, it's evident that bash failed somewhere along the way – I would say at being a plain POSIX shell, which would be a bug. – user2394284 Aug 28 '19 at 17:18
0

So what caused it was I am sourcing some bash scripts in my ~/.bashrc file like so:

for f in "$HOME/.oresoftware/bash/"*; do
   . "$f"
done;

so I just changed it to:

for f in "$HOME/.oresoftware/bash/"*; do
  if [[ "$(basename "$0")" != 'sh' ]]; then
      # source only if not using sh
      . "$f"
  fi
done;

so in theory if it's called by sh then it won't try to source those files, but not sure if this work 100% of the time.

Alexander Mills
  • 9,330
  • 19
  • 95
  • 180