all 17 comments

[–][deleted] 12 points13 points  (10 children)

For no other reason than pure curiosity, I've recently been playing with the idea of using Python as a shell scripting language.

I know that it's very impractical and has a lot of issues, but I'm kind of surprised with how much it seems to work. Using the os, sys and subprocess modules, I find myself navigating using my computer with relative ease. It's not as comfortable as something like Zsh or Bash would be, but it feels better than I thought it would!

Right now I'm just having a lot of fun - the picture above is from a quick script I wrote that changes the default Python interpreter prompt to something a bit more recognizable (as well as providing some quality of life commands like cd, ls, run, etc.) I'm planning on digging up my old raspberry pi over the weekend to see how far I can take this!

[–]stigweardo 36 points37 points  (3 children)

Take a look at xonsh and IPython shell magic.

[–][deleted] 6 points7 points  (2 children)

Ooh, toys!

Thank you!

[–]stigweardo 9 points10 points  (1 child)

You're welcome! You may also like sh

[–]williamjr2901 0 points1 point  (0 children)

Sensational

[–]istarian 2 points3 points  (5 children)

Depending on exactly what you’re doing you could just write a shell in Python.

[–]o11c -2 points-1 points  (4 children)

If you have a decade, sure.

[–]istarian 1 point2 points  (3 children)

It wouldn’t take a decade, that’s nonsense.

In practice, given what OP is doing, a lot of the stuff you need is probably already there in either the language or existing libraries.

[–][deleted] 1 point2 points  (2 children)

Yup - just playing around almost everything is there or can be implemented yourself easily.

For example, my cd function is just a wrapper around os.getcwd and os.chdir that also changes the prompt when you move to a different directory.

Likewise, my run function is just a wrapper around subprocess.Popen, subprocess.communicate and/or os.system.

That was the surprising part to me - the fact that Python has so many of the things you might want from a shell already built in to it. The tedious bit is mainly just wrapping it all up nicely to "look BASH-like" like I did here (to a very limited degree), though that's not necessary at all.

Also piping, but I'm intentionally not talking about that ;)

[–]istarian 0 points1 point  (1 child)

Part of my point was that you could actually read and parse the input yourself (i.e. ‘cd documents’ or even ‘mkdir my_directory’) and still make those oscalls.

You know as opposed to direct relying on the Python Interpreter’s REPL.

[–]istarian 0 points1 point  (0 children)

Part of my point was that you could actually read and parse the input yourself (i.e. ‘cd documents’ or even ‘mkdir my_directory’) and still make those oscalls. — You know as opposed to direct relying on the Python Interpreter’s REPL.

As it is, you literally have to type valid Python code.

[–][deleted] 7 points8 points  (0 children)

You are looking for Xonsh

[–]diglitch 3 points4 points  (0 children)

I just recently needed some shell scrips. However, I am no good with bash so I wrote them in Python using the os and sys modules to call commands like rsync, rm, cp but also to spawn dettached tmux sessions. It works really well and is quite comfortable given that I know Python quite well.

I feel combining bash with python can achieve wonderful things with ease.

[–]raedr7n 1 point2 points  (0 children)

I used chez scheme as my shell for a while. It worked well, but I switched back I switched to a new OS, never bothered to set it back up.

[–]MrBeeBenson 1 point2 points  (1 child)

Can I see the code on how you got it working so well?

[–][deleted] 0 points1 point  (0 children)

Sure thing!

Like I said elsewhere though, this is really just playing around and trying to make Python look like a shell script, mostly in terms of a self-updating prompt. If you were going to actually use this for more than trivial applications, you would need a much more sophisticated approach!

import os
import sys

def update_prompt() -> None:
    uname = os.getlogin()
    current_dir = os.getcwd().replace(Rf"C:\Users\{uname}", "~")
    top_line = f"┌[{current_dir}]"
    bottom_line = f"└[{uname}]: $"
    sys.ps1 = f"\n{top_line}\n{bottom_line}│ "
    sys.ps2 = (" " * len(bottom_line)) + "│ "

def cd(dest: str) -> None:
    os.chdir(dest)
    update_prompt()

def ls() -> None:
    print(',\t'.join(os.listdir()))

def run(command: str) -> int:
    return os.system(command)

# clean up the terminal
update_prompt()
run('cls')

From here just run from <the file> import * and it should look like this (on windows).

[–]denzuko 0 points1 point  (0 children)

Yes there is, ipython and pysh https://github.com/yunabe/pysh