I am working on Mac OS X and I have a Python script which is going to be called by other scripts and programs (Apple's launchd in particular). I could call it with
python /Users/xyz/long/absolute/path/to/script.py arg1 arg2
Since the location of the script might change, I want to decouple other scripts and the launchd configuration files from the actual location, so that a call to the script looks like
script arg1 arg2
Defining an alias for Bash in $HOME/.bash_profile does not work, since launchd does not know about the alias.
What is the best way to define a "sytem-wide alias" or something equivalent?
I usually make a symbolic link and put it in /usr/bin (assuming /usr/bin is part of your PATH)
(In a terminal. You may have to use sudo ln -s depending on the permissions.
ln -s /Users/xyz/long/absolute/path/to/script.py /usr/bin/script.py
If you take Rory's advice and put the #!/usr/bin/python at the beginning of the script, you'll also need to make the script executable.
chmod a+x /Users/xyz/long/absolute/path/to/script.py
As well as doing a symlink, you can put "#! /path/to/python" at the start of the script and make it executabe. Then you don't have to call it with "python /Users/big/long/path/script.py"
Related
Context:
I'm working with a few developers, some on OSX and some on Linux. We use a collection of bash scripts to load environment variables, build docker images etc. The OSX users are using zsh instead of bash, so some tricks (specifically how we're getting the running script's directory) aren't compatible. What works on Linux (but not OSX) is:
$ cat ./scripts/env_script.sh
THIS_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
# ... more variables ...
$ source ./scripts/env_script.sh
$ echo $THIS_DIR
# the absolute path to the scripts directory
Some cursory testing shows this doesn't work on OSX, presumably because BASH_SOURCE doesn't work the same with zsh. Fine.
Goal:
We're all working with a Python, we would like to replace our bash scripts with Python.
The same pattern is very easy in Python.
from pathlib import Path
THIS_DIR = str(Path(__file__).parent)
Not the cleanest, but it works anywhere. Ideally we could run this and share THIS_DIR with the shell that called the script. Something like
$ <answer to my question> ./scripts/env_script.py
$ echo $THIS_DIR
# absolute path to the scripts directory
Question:
Suppose we rewrote our ./scripts/env_script.sh into ./scripts/env_script.py and collected a list of variables we would like to share with the calling environment.
That is, we wrote the Python script above.
Is it possible to do something akin to source ./scripts/env_script.py so that we can export the variables from the Python script into the calling shell?
What I've tried:
I found a potential duplicate here though the answer is basically 'Python runs in a sub-process, source would only work if your shell is Python` which makes sense but doesn't answer the question.
If there isn't a nice way to exchange these variables, then another option would basically be to have the Python script spit the variables to stdout and then eval them within my shell. I.e. eval $(./script/env_script.py). I guess this could work, but it feels wrong at least because I was always taught eval is evil.
I spent a little more time on the second solution since I could imagine it working (although I'm not happy with it). Basically, I rewrite ./scripts/env_script.py to be
FOO='whatever'
THIS_DIR=str(Path(__file__).parent)
# and so on...
# prints all "normal" variables to stdout
def_vars = list(locals().items())
for name, val in def_vars:
if name.startswith("_"):
continue
print(f'{name}="{val}"')
So running it normally would output
$ ./scripts/env_script.py
FOO="whatever"
THIS_DIR="..."
...
$ echo $FOO
# nothing
Then, to jam those variables into the calling shell, we wrap that with eval and it does the job
$ eval $(./scripts/env_script.py)
$ echo $FOO
whatever
I guess with some further tweaking, the footer at the end of env_script.py could be made a little more robust, and then moved outside of the script. Some sort of alias could be defined to make it syntactically nicer, so then calling it could like pysource ./scripts/env_script.py. Still, I'm not satisfied with this answer.
Edit: I did the tweaking and wrote a downloadable script here.
Nothing happens when executing a python shebang script in /usr/local/bin/
Hopefully someone can help me. So i made a simple python program called test for testing out shebang scripts(I have used chmod to make it executable):
#!/usr/bin/python
print "hello"
after i copied it to /usr/local/bin/ i tried to call it by typing in
my shell:test
but nothing happened...
(There were no errors)
Adrian
test is actually a shell builtin:
$ type test
test is a shell builtin
Rename your script to something else or run it directly by executing /usr/local/bin/test.
Blender is right: 'test' is an unfortunate name choice for your file. There is already a shell builtin function called 'test'. It would be the same if you tried to make a python script called 'ls'. The reason it works when executing './test' is due to the fact that './' tells the shell to make the current directory first in the executable path. If you rename your python script to 'bangtest' and make sure it has executable permissions (chmod +x bangtest), it will work in the manner you desire.
Yes, I know I can do
python2 cal.py
What I am asking for is a way to execute it on the command line such as:
calpy
and then the command afterwards. I put in in a path and when I write cal.py in the command line:
/usr/bin/cal.py: line 5: print: command not found
I don't want to issue cal.py to run my script, I want it to be issued with calpy
I'm running Arch Linux if that helps, thanks. Sorry for my English.
In order for bash to know to run your script via the Python interpreter, you need to put an appropriate shebang at the start. For example:
#!/usr/bin/python
tells bash to run /usr/bin/python with your script as the first argument. I personally prefer
#!/usr/bin/env python
which is compatible with virtualenv. You also need to ensure that the permissions on your script allow it to be executed:
~$ chmod +x path/to/cal.py
Finally, in order to call cal rather than path/to/cal.py, you need to remove the .py extension and make sure that the directory containing cal is in your command search path. I prefer to add ~/bin to the search path by modifying the $PATH environment variable in ~/.bashrc:
export PATH=$HOME/bin:$PATH
then put my own executables in ~/bin. You could also copy (or symlink) cal to one of the system-wide binary directories (/bin or /usr/bin), but I consider it bad practice to mess with system-wide directories unnecessarily.
Ok, you need a couple of things for achive what you want.
First you have to tell your script "How" is going to execute/interpret it. You can do this writting
#/usr/bin/env python
at the very beggining of the file.
The problem you have is the system is trying to execute the script using bash. And in bash there is no print command.
Second you need give execution privileges to your script. And of course if you want to call your script through the command "calcpy", the script has to be called like that.
Put this (exactly this) as the first line of your script:
#!/usr/bin/env python
I have been searching the web for an answer now for quite a while, but this is giving me really headache:
I am using Ubuntu 12.04 and I want to execute a Python script from the terminal without using the full path.
So i added /home/kyril/python/scripts/ to the PATH variable through putting the following into ./bashrc:
kyrilpathvariable="/usr/lib/lightdm/lightdm:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/home/kyril/Python/scripts/:/home/kyril/Bash/scripts"
if [ "$kyrilpathvariable" = "$PATH" ]; then
echo PATH already exported
else
PATH=$PATH:/home/kyril/Python/scripts/
PATH=$PATH:/home/kyril/Bash/scripts/
export PATH
fi
(I know the if clause is not necessary but I did not like to have everything two times in my PATH if I type exec bash.)
Now the problem: this perfectly works for my Bash scripts, so after making them executable via chmod I can just type $ script.sh and it is executed. However if I type $ python3 script.py the following error is raised: python3: can't open file 'script.py': [Errno 2] No such file or directory
if I type in the full path to the script it works. Anybody has an idea what I am doing wrong? Do I have to add the directory to the PYTHONPATH? (As I understood this only helps for importing modules).
Thanks guys!
When invoking python3 directly, python runs the script file you told it to, without using $PATH to find it. PYTHONPATH is irrelevant--that's used for searching for Python modules.
I'm guessing you're having issues with the wrong interpreter getting invoked when you run script.py by itself. I don't know what the first line of your script is, but it should be this:
#!/usr/bin/env python3
Or if you need even finer control:
#!/usr/bin/env python3.2
And for Python 2 scripts:
#!/usr/bin/env python2
Or:
#!/usr/bin/env python2.7
You should check that these executables exist on your system before trying to use them.
I would guess that path variables are ignored when python searches for the input-file. Python starts searching for 'script.py' in the current directory, not knowing that there is a path variable declared for that file, and therefore cannot find it.
Unfortunately I'm not sure how to solve it but maybe someone more experienced with variables can enlighten us?
python3 $(type -P script.py)
Tells Bash to look in the PATH for the executable file and supply its location and name.
For example:
$ type -P script.py
/usr/local/bin/script.py
To avoid duplicate entries in the path, you can do:
for dir in Python Bash; do
dir_to_add="$HOME/$dir/scripts"
case ":$PATH:" in
*:"$dir_to_add":*) ;; # path already contains dir, do nothing
*) PATH+=":$dir_to_add" ;;
esac
done
I previously used to copy Python/Perl scripts to access from my bash script. Duplication is not a good idea I know! Is there a way to call them from bin or libs folder that we have set up?
For instance :
My python script resides in /home/ThinkCode/libs/python/script.py
My bash script resides in /home/ThinkCode/NewProcess/ProjectA/run.sh
Now I want to use/call script.py from run.sh
Thank you!
Make this the first line of your python script (bash will then know this is a python script and it should be run with python):
#/usr/bin/env python
EDIT: my bad, it should be #!/usr/bin/env python not #!/usr/bin/python. It is better to do it this way.
Then chmod your script with u+x (if not a+x).
Now your python script works as an executable. Your bash script, then, can call it like you'd call any executable.
Just do python /path/to/my/python/script.py.
In a bash script, you execute programs the same way you do from the bash command prompt.
/home/ThinkCode/libs/python/script.py
If this doesn't launch the script directly, you may need to add python to the beginning (like this: python /home/ThinkCode/libs/python/script.py) and/or ensure that the script is executable (with chmod +x /home/ThinkCode/libs/python/script.py).