1

I have a sh (shebang #!/bin/sh) script (sh.sh) which invokes a bash (shebang #!/bin/bash) sub-script:

. "some-path/bash.sh"

In the bash script I have a declaration of an associative array: declare -A properties, thus getting the error declare: not found.

It's obvious why declare isn't found as the parent script is a sh script and not bash.

Is there a way to force bash syntax?

Another way is to open a new shell, but it's problematic because the subscript's purpose is to define variables to be used in the parent script. Sub-shells shouldn't be messing with parent's variable.

Parent (sh.sh):

#!/bin/sh
. "some-path/bash.sh"

Child (bash.sh):

#!/bin/bash
declare -A properties

Usage I was trying:

./sh.sh
3
  • Please edit your question and give us enough of the script to reproduce the issue.
    – terdon
    Jul 18, 2016 at 16:05
  • 1
    Note: do not use file extensions for executable files. It is bad form, and makes if difficult if you were to rewrite in python, perl, C (as the extension would change, and all programs that call your program would have to change). Jul 18, 2016 at 16:08
  • @terdon - Added scripts to reproduce. Jul 18, 2016 at 16:11

3 Answers 3

3

Do not source the script (source script or . script).

Instead just run it normally script.

4
  • Won't your proposal open a new shell? I'd like to avoid this because the sub-script defined variable that should be used by the parent script. Jul 18, 2016 at 16:07
  • 4
    If you want to avoid creating a new shell, then it is mathematically impossible for the new shell to be bash (as there is no new shell). Re-write everything, so that it is all in the same language. Jul 18, 2016 at 16:11
  • @AlikElzin-kilaka If you use export on a variable at any point, it becomes visible to subprocesses. var=blah; : do_stuff_with var; export var; bash -c 'echo "$var"'. However, these subprocesses cannot modify the variable. One way around that would be to use a pipe to transfer state from that shell to yours once you're done. Jul 29, 2016 at 14:12
  • @Score_Under a sub-process can modify an environment-variable, but its new value is only visible to it self, and is passed to its sub-processes (when they start). Therefore, as you say, environment-valiables are no good for back communication. They are also not real-time (you can only send a message as the process is started. Aug 11, 2016 at 16:19
2

Instead of running the parent script as is: ./sh.sh, I ran it using bash: bash sh.sh. Worked.

I have a hidden assumption that sh is a subset of bash. Not sure if it's correct, but worked.

7
  • 1
    Whether sh is a subset of bash or not will depend on what sh actually is on your system. You haven't told us what OS you're using so we can't know that. That said, your question shows you're sourcing the script (. script.sh) but your answer shows you executing it. Which is it?
    – terdon
    Jul 18, 2016 at 16:06
  • I'm executing the parent which sources the child. Jul 18, 2016 at 16:08
  • 2
    Yes, it works, but you're making your code needlessly brittle. The child program is a bash script because it starts with #!/bin/bash. The kernel knows how to execute that. So just call the child script directly. Jul 18, 2016 at 23:46
  • 1
    I don't have control over the parent script. I'm just executing it and it executes a my "plugin" script. See example "catalina.sh" file. Mine is "setenv.sh": github.com/magro/msm-sample-webapp/blob/master/runtime/… Jul 19, 2016 at 4:13
  • 1
    maybe call awk or perl from your sourced script? you're not going to able to return the array anyway, only use it within that script.
    – cas
    Jul 19, 2016 at 7:01
0

For Ubuntu compatibility, I wrote this, which recalls the script with it's options under bash and returns the same exit code.

#!/bin/bash
if [ `readlink /proc/$$/exe` != "/bin/bash" ];then
  bash "$0" "$@"
  exit $?
fi
echo "Shell: "`readlink /proc/$$/exe`

edit: Good catch, fixed

5
  • Note that since you don't quote any of the expansions, your code will not cope with arguments containing spaces or filename globbing characters (under some conditions). It would also break if $0 contains spaces. Also note that re-executing the current script with bash could potentially break the script. It would be much better and safer to just write bash shell code from the start without trying to compose polyglot scripts. Treat each shell as if they were separate languages. You would not mix Perl with Ruby or Python.
    – Kusalananda
    Sep 25, 2020 at 15:02
  • So the reason I needed this, is that someone was calling all scripts as /bin/sh in an Ubuntu environment. In Ubuntu /bin/sh points to dash. So I added this to the head of my bash scripts for protection and redirection as shells do not respect the #!/bin/bash that is also there.
    – GET
    Sep 30, 2020 at 14:41
  • It feels like you're trying to come up with a technical solution to something that in essence is a social problem. Ask them to run your script with the correct interpreter, and also mention this in the documentation.
    – Kusalananda
    Sep 30, 2020 at 15:54
  • Completely is. Cannot get them to understand that sh is fluid while dash bash are fixed; and why that's important.
    – GET
    Sep 30, 2020 at 17:32
  • Maybe just tell them to invoke an sh wrapper that runs your script? I.e. split it in two: wrapper script written for sh (or whatever shell), calling the real script without explicit interpreter.
    – Kusalananda
    Sep 30, 2020 at 17:59

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.