A script can check its Python version and, if that's Python 3, re-start itself using Python 2. Add the following near the head of the script:
if sys.version > '3':
python2 = os.popen('which python2 2> /dev/null').read().rstrip()
if python2:
args = sys.argv[:]
args.insert(0,python2)
os.execv(python2,args)
else:
sys.exit("%s requires Python Version 2 (python2 not in PATH)" % os.path.basename(__file__))
This uses the system's which
command to locate python2
in the environment's PATH
. It then relaunches itself with that (or aborts if unable to find it).
Note that the script does need to be valid Python 3 syntax for it to start in Python 3.
Also, any output should be flushed before the execv
call or it will be lost. Adding, for example, sys.stdout.flush()
just before the call to execv
will flush any print
statements.
Early shells had only a single data type: strings. But it is common to manipulate lists of strings, typically when passing multiple file names as arguments to a program. Another common use case for splitting is when a command outputs a list of results: the command's output is a string, but the desired data is a list of strings. To store a list of file names in a variable, you would put spaces between them. Then a shell script like this
files="foo bar qux"
myprogram $files
called myprogram
with three arguments, as the shell split the string $files
into words. At the time, spaces in file names were either forbidden or widely considered Not Done.
The Korn shell introduced arrays: you could store a list of strings in a variable. The Korn shell remained compatible with the then-established Bourne shell, so bare variable expansions kept undergoing word splitting, and using arrays required some syntactic overhead. You would write the snippet above
files=(foo bar qux)
myprogram "${files[@]}"
Zsh had arrays from the start, and its author opted for a saner language design at the expense of backward compatibility. In zsh (under the default expansion rules) $var
does not perfom word splitting; if you want to store a list of words in a variable, you are meant to use an array; and if you really want word splitting, you can write $=var
.
files=(foo bar qux)
myprogram $files
These days, spaces in file names are something you need to cope with, both because many users expect them to work and because many scripts are executed in security-sensitive contexts where an attacker may be in control of file names. So automatic word splitting is often a nuisance; hence my general advice to always use double quotes, i.e. write "$foo"
, unless you understand why you need word splitting in a particular use case. (Note that bare variable expansions undergo globbing as well.)
Best Answer
That thread and its accepted answer in particular are about using Python for shell scripting, not as an interactive shell.
To write scripts in a different language, put e.g.
#!/usr/bin/env python
instead of#!/bin/bash
at the top of your script.If you want to try out a different interactive shell, just run it, e.g. type
ipython
at your existing shell prompt. If you've decided to adopt that shell, set theSHELL
environment variable at the start of your session (in~/.profile
in most environments, or in~/.pam_environment
), e.g.export SHELL=/usr/bin/ipython
(.profile
syntax) orSHELL="/usr/bin/ipython"
(.pam_environment
syntax).None of the shells that I've seen based on advanced languages such as Perl or Python are good enough for interactive use in my opinion. They're too verbose for common tasks, especially the common job of a shell which is to launch an application. I wrote about a similar topic 4 years ago; I don't think the situation has fundamentally improved since then.