Future-proof your skills with Linux, Python, vim & git as I share with you the most timeless and love-worthy tools in tech through my two great projects that work great together.

Python Virtual Env Better Than /usr/local/sbin

I've improved my process for editing multiple files in NeoVim with an `all` script. This script is now located in the /bin folder of my Python virtual environment, making the system more flexible and allowing me to switch between machines easily. I wrote a new script to help with this process, and I'm now able to pull from my git repos, copy the files to the correct locations, edit them in NeoVim, and push the changes back to my git repos.

Optimizing my Editing Process with a New `all` Script in NeoVim

By Michael Levin

Thursday, April 27, 2023

My life becomes better if my all script were more editable, and in fact was one of its own files loaded. It then becomes much more meta. Are there other locations as good as /usr/local/sbin for this sort of thing? First, look at my environment path variable.

Do an experiment putting a Python script with no .py extension but with the execute bit set in ~/bin and see if you get the same effect…

mkdir ~/bin
sudo mv /usr/local/sbin/all ~/bin/
sudo chown ubuntu:ubuntu ~/bin/all

Nope, like I thought, that folder had to be made so couldn’t possibly be in the existing path. Look at the path. How again? Oh yeah, printenv!

Well, there’s /usr/sbin which sounds promising!

[py311] ubuntu@LunderVand:~/repos $ cd /usr/sbin
[py311] ubuntu@LunderVand:/usr/sbin $

It exists! Woot! And it’s in the already existing path. Both very good signs. I guess I’ll be moving startjupyter there too from the drinkme project, but I’ll do that later.

sudo mv ~/bin/all /usr/sbin/

Yep, confirmed that works! Okay, make that the permanent new location. It also couldn’t hurt to run drinkme again, maybe even with the .config folder Windows-side renamed to get that error I saw yesterday when switching machines.

Wow, worth noting that /usr/sbin is full of stuff! Almost certainly from Debian-like apt installs under Ubuntu. Okay, noted.

Best laid plans, ugh! You still need to sudo to edit files in /usr/sbin even if it’s owned by the non-admin user (sudo chown ubuntu:ubuntu).

Ugh! Compomise a little. Let’s try putting it in the bin folder of the Python virtual environment:

cp /usr/sbin/all /home/ubuntu/py311/bin/

Works from there! Now let’s make sure I didn’t leave any “all” files around. Okay now let’s edit it in that location (which can be abbreviated as ~/py311/bin).

Okay, so now I have by all script in a location that’s in my path, and I can edit it without sudo. The tricky part was making sure that when I edit files that are outside repos, such as my init.vim and all, that when I switch to a new machine and run all there, it actually has everything. There’s extreme order-sensitivity on what you copy where when during the process.

But I have it workd out and am very comfortably moving between 2 machines. And when I do move like that, a system I built for myself for journaling moves with that. There’s a vision developing here.

Okay, done. And my process is permanently improved moving forward. I have a new coding style developing that makes heavy use of Figlet ASCII art.

The valuable ability I find from putting things in /usr/local/sbin of being able to run a Python script from anywhere without having to specify the location is preserved. I can run all from anywhere, and it will ensure all my regularly edited files are loaded into buffers.

One of those buffers now contains the all script itself, which I was not able to do while it was in the old location that offered that advantage. In looking for a new location (early in the console “path” environment variable), I discovered that the /bin folder of the Python virtual environment is in the path, and there was no downside to putting it there.

The upside of making it one of the very files its loading to edit makes the whole system come alive and be subject to rapid refinement and improvement, and indeed a more flexible life because the files that are pre-loaded for editing are sort of a snapshot of what’s going on in your life.

Wheras I was hesitant to edit the all script when it was in the old location, I’m not hesitant to edit it now. And so now I’m in a more flexible state of what the “text files of my life” are.

And the final nuance I worked out is how to make this work well when switching around to different machines. I have to make sure I copy the right files to the right places at the right times. For example, I do a git pull on all my repos before I begin editing in case I’ve made edits from another machine. However, some of the files live outside of repos, such as my init.vim and my all, and for those to be in sync, I have to copy them out of the repos and into location before loading them into NeoVim to edit. So there’s a copy-files and a reverse-copy function. The reverse-copy runs immeidately after the git pull.

Here’s the new code for the new all script:

#! /usr/bin/env python
#        _             _ _           _ _
# __   _(_)_ __ ___   (_) |_    __ _| | |   Why edit 1 file when you can
# \ \ / / | '_ ` _ \  | | __|  / _` | | |   edit everything all at once?
#  \ V /| | | | | | | | | |_  | (_| | | |   Why mess with tabs when you can
#   \_/ |_|_| |_| |_| |_|\__|  \__,_|_|_|   :bn into buffers?

import shlex
import shutil
from os import system
from os import getuid
from sys import stdout
from time import sleep
from pwd import getpwuid
from pyfiglet import Figlet
from subprocess import Popen, PIPE

# Get Linux Username for portability between systems
USERNAME = getpwuid(getuid())[0]
GIT_EXE = "/usr/bin/git"
REPOS = f"/home/{USERNAME}/repos/"
HIDE = f"{REPOS}hide/"

# Files to edit
edit_files = [

# Places to put files after editing
copy_to_destination = {
    "/home/ubuntu/py311/bin/all": f"{REPOS}vim/all",
    "/home/ubuntu/.config/nvim/init.vim": f"{REPOS}vim/init.vim",

# Repos to push after editing
git_repos = [

# Load function early so we can use it, pronto!
def fig(text, description=None, font="standard"):
    #  _____ _       _      _
    # |  ___(_) __ _| | ___| |_
    # | |_  | |/ _` | |/ _ \ __|
    # |  _| | | (_| | |  __/ |_
    # |_|   |_|\__, |_|\___|\__|
    #          |___/
    """Let them see text!"""
    f = Figlet(font=font)
    if description:

def flush(std):
    """Flush a stream."""
    for line in std:
        line = line.strip()
        if line:

def git(cwd, line_command):
    """Run a Linux git command."""
    cmd = [GIT_EXE] + shlex.split(line_command)
    show_cmd = " ".join(cmd)
    print(f"Running: {show_cmd}")
    process = Popen(

def git_pull():
    for arepo in git_repos:
        fig(f"{arepo.split('/')[-1]}", font="cybermedium")
        git(arepo, "pull")

def load_editor():
    print("Loading editor...")
    files = " ".join(edit_files)
    command = f"nvim {files}"

def git_push():
    for repo in git_repos:
        fig(f"{repo.split('/')[-1]}", font="cybermedium")
        print(f"Pushing {repo} to Github...")
        git(repo, "commit -am 'pushing to github...'")
        git(repo, "push")

def copy_files():
    for source, destination in copy_to_destination.items():
        print(f"Copying {source} to {destination}")
        shutil.copyfile(source, destination)

def reverse_copy():
    for destination, source in copy_to_destination.items():
        print(f"Copying {source} to {destination}")
        shutil.copyfile(source, destination)

fig("vim it all...", "Loading data into multiple vim buffers\n")

# Main Control Flow