Wednesday, July 27, 2022

[SOLVED] Return Values from Python Script to Bash Script is different when used with Print Statement

Issue

I have a bash command that is as below:

    dependencies=$(/path/to/my-profiles.py --my-profiles pytest)
    IFS=' ' read -r -a arr <<<"$dependencies"
    declare -p arr

    for i in "${arr[@]}"
    do
        echo "$i"
    done

And my Python script is as below:

my-script.py
def main():
    parser = argparse.ArgumentParser(description='My script')
    parser.add_argument('--my-profiles', dest="profiles", 
                        type=str,
                        default='')
    parsed_args = parser.parse_args()
    dependencies = get_dependencies(args.profiles)
    return dependencies

def get_dependencies(profiles):
    return ' '.join([
       'mock-alchemy', 'pytest-mock', 'pytest-datafixtures', 'pytest-describe', 'pytest-unordered', 'requests-mock'
       ])

When I run the bash script with the above python script, I get the output as below:

mock-alchemy pytest-mock pytest-datafixtures pytest-describe pytest-unordered requests-mock
declare -a arr='()'

However, if I add print statement in my python script I get the result as I want:

my-script.py
def main():
    parser = argparse.ArgumentParser(description='My script')
    parser.add_argument('--tox-profiles', dest="profiles", 
                        type=str,
                        default='')
    parsed_args = parser.parse_args()
    dependencies = get_dependencies(args.profiles)
    print(dependencies)
    return dependencies

def get_dependencies(profiles):
    return ' '.join([
       'mock-alchemy', 'pytest-mock', 'pytest-datafixtures', 'pytest-describe', 'pytest-unordered', 'requests-mock'
       ])

With addition of print statement in the script, I get the below result:

mock-alchemy pytest-mock pytest-datafixtures pytest-describe pytest-unordered requests-mock
declare -a arr='([0]="mock-alchemy" [1]="pytest-mock" [2]="pytest-datafixtures" [3]="pytest-describe" [4]="pytest-unordered" [5]="requests-mock")'
mock-alchemy
pytest-mock
pytest-datafixtures
pytest-describe
pytest-unordered
requests-mock

I want my solution to as the second type, but I do not want to add a print statement. I want to know what am I doing wrong and how can I fix it?


Solution

main can return a value, but that isn't exposed to the shell in any way. You cannot return arbitrary data from one process to another; you can only write to a file (using "file" in the loosest sense; could be a disk file, a socket, a pipe, etc.)

Writing the results to standard output and letting the shell capture that output, as you are doing, is the standard method for a child to communicate with its parent.

As such, the return statement is unnecessary.

def main():
    parser = argparse.ArgumentParser(description='My script')
    parser.add_argument('--tox-profiles', dest="profiles", 
                        type=str,
                        default='')
    parsed_args = parser.parse_args()
    dependencies = get_dependencies(args.profiles)
    print(dependencies)


Answered By - chepner
Answer Checked By - Timothy Miller (WPSolving Admin)