Importing functions from a shell script

前端 未结 4 666
南旧
南旧 2020-12-12 14:18

I have a shell script that I would like to test with shUnit. The script (and all the functions) are in a single file since it makes installation much easier.

Example

相关标签:
4条回答
  • 2020-12-12 14:47

    If you are using Bash, a similar solution to @andrewdotn's approach (but without needing an extra flag or depending on the script name) can be accomplished by using BASH_SOURCE array.

    script.sh:

    #!/bin/bash
    
    foo () { ... }
    bar () { ... }
    
    main() {
        code
    }
    
    if [[ "${#BASH_SOURCE[@]}" -eq 1 ]]; then
        main "$@"
    fi
    

    run_tests.sh:

    #!/bin/bash
    
    . script.sh
    
    # Unit tests
    
    0 讨论(0)
  • 2020-12-12 14:56

    If you are using Bash, another solution may be:

    #!/bin/bash
    
    foo () { ... }
    bar () { ... }
    
    [[ "${FUNCNAME[0]}" == "source" ]] && return
    code
    
    0 讨论(0)
  • 2020-12-12 15:00

    Picked up this technique from Python, but the concept works just fine in bash or any other shell...

    The idea is that we turn the main code section of our script into a function. Then at the very end of the script, we put an 'if' statement that will only call that function if we executed the script but not if we sourced it. Then we explicitly call the script() function from our 'runtests' script which has sourced the 'script' script and thus contains all its functions.

    This relies on the fact that if we source the script, the bash-maintained environment variable $0, which is the name of the script being executed, will be the name of the calling (parent) script (runtests in this case), not the sourced script.

    (I've renamed script.sh to just script cause the .sh is redundant and confuses me. :-)

    Below are the two scripts. Some notes...

    • $@ evaluates to all of the arguments passed to the function or script as individual strings. If instead, we used $*, all the arguments would be concatenated together into one string.
    • The RUNNING="$(basename $0)" is required since $0 always includes at least the current directory prefix as in ./script.
    • The test if [[ "$RUNNING" == "script" ]].... is the magic that causes script to call the script() function only if script was run directly from the commandline.

    script

    #!/bin/bash
    
    foo ()    { echo "foo()"; }
    
    bar ()    { echo "bar()"; }
    
    script () {
      ARG1=$1
      ARG2=$2
      #
      echo "Running '$RUNNING'..."
      echo "script() - all args:  $@"
      echo "script() -     ARG1:  $ARG1"
      echo "script() -     ARG2:  $ARG2"
      #
      foo
      bar
    }
    
    RUNNING="$(basename $0)"
    
    if [[ "$RUNNING" == "script" ]]
    then
      script "$@"
    fi
    

    runtests

    #!/bin/bash
    
    source script 
    
    # execute 'script' function in sourced file 'script'
    script arg1 arg2 arg3
    
    0 讨论(0)
  • 2020-12-12 15:06

    According to the “Shell Builtin Commands” section of the bash manpage, . aka source takes an optional list of arguments which are passed to the script being sourced. You could use that to introduce a do-nothing option. For example, script.sh could be:

    #!/bin/sh
    
    foo() {
        echo foo $1
    }
    
    main() {
        foo 1
        foo 2
    }
    
    if [ "${1}" != "--source-only" ]; then
        main "${@}"
    fi
    

    and unit.sh could be:

    #!/bin/bash
    
    . ./script.sh --source-only
    
    foo 3
    

    Then script.sh will behave normally, and unit.sh will have access to all the functions from script.sh but will not invoke the main() code.

    Note that the extra arguments to source are not in POSIX, so /bin/sh might not handle it—hence the #!/bin/bash at the start of unit.sh.

    0 讨论(0)
提交回复
热议问题