How do I pass variables to shell functions in Python?
Question: I would like to write a Python script to automate the process of adding the
dependencies of a npm package to my Open Build Service project. I have a shell
function:

    
    
    function cpobsn {
        cdobsa
        mkdir nodejs-$1
        cd nodejs-$1
        npm2PKGBUILD $1 > PKGBUILD
        cpserv
        obsa
    }
    

this is the Python script I have at the moment (the `package.json` file being
imported is the `package.json` of the npm package):

    
    
    import json
    import os
    
    with open("/home/fusion809/OBS/home:fusion809:arch_extra/arch-wiki-man/package/package.json") as json_file:
        json_data = json.load(json_file)
        deps = json_data["dependencies"]
        for key, value in deps.items():
            print(key)
            os.system("cpobsn")
    

I would like to pass the `key` variable to the `cpobsn` shell function (i.e.,
I would like this Python loop to run the shell command `cpobsn key` on every
iteration). How do I do this?


Answer: Functions are good for interactive use, but this seems like a case where you
want a stand-alone script instead.

If you want to have a function you can load into your `.zshrc` or similar, you
could do something like the Python `__name__ == '__main__'` idiom in the
script file, too. But renaming the file to the name of the command and getting
rid of the function would seem like the simplest way to achieve your end goal
here.

Save this as, say, `$HOME/bin/cpobsn` and `chmod +x` it. Make sure `$HOME/bin`
is in your `PATH`, too.

    
    
    #!/bin/sh
    cdobsa
    mkdir nodejs-"$1"
    cd nodejs-"$1"
    npm2PKGBUILD "$1" > PKGBUILD
    cpserv
    obsa
    

(Note the addition of proper quotes for good measure.)

Now, you can call it from Python, as with any regular external command.

    
    
    from subprocess import check_call
    check_call(['cpobsn', key])
    

The choice between `subprocess.call()` and `subprocess.check_call()` will
depend on whether the script returns a useful exit code. It doesn't at the
moment, so actually `call` would be sufficient; on the other hand, you should
fix that, and use `check_call` to have Python tell you when some part of the
shell script failed.

Minimally, adding `set -e` to the shell script will make it check for errors,
and abort if anything fails; but this often requires refactoring to avoid
terminating on non-fatal errors (like `grep` not returning a result -- this is
technically an error, but often an acceptable part of normal flow).

