Start all of your commands with a comma (2009)

6 years ago (rhodesmill.org)

This is clever given what we have, but it seems like the wrong solution to the problem.

I already have a PATH order. What would be nice is if typing say `sc` gave me the first `sc` program, but typing `,sc` gave me the one after that.

This would generalize, so if I were stuck with cough several pythons I could call them with `python`, `,python`, `,,python` and so forth.

This would be a shell-level patch but surely not an impossible one.

Ironically, the one person whose workflow this would clobber is the one who wrote this blog post!

  • You could write a script called, say, "," that does this. ", sc" could invoke the second "sc" command in your $PATH, and ",, sc" could invoke the third. (What to do if there's only one "sc" in $PATH is left as an exercise.)

  • Pythons (AFAIK?) Are aliased under two levels of their version, so you should be able to run python, python3, and python3.8 (or whatever). I suspect that you can also do something nasty with symlinks to extend that further into virtual environments, but I've never tried it.

  • that would require one to keep in mind all the $PATH values and their order, which doesn't sound fun.

    • I'd say it only requires you to keep in mind "crap, that's right, I installed another `sc`, the one I want is `,sc` now", and only for the few name collisions you have to deal with.

      A good shell like fish could provide the full path name as a hint for any use of ,

Seemingly this is just as a cheap version of namespacing or something in the event something comes out that uses the same name as a name you chose, rather than actually being about "overriding"?

Because otherwise why not just do what I assume everyone else does, and put ~/bin before everything else on your PATH?

  • It’s to avoid collisions altogether, not to prioritize the custom commands over the standard ones.

    For example, let’s say I have a script that improves upon the systemctl command, and I want to use it all the time and not type a bunch of characters to invoke it. I might call it “sc”, forgetting that I also use the spreadsheet calculator sometimes.

    If I always prefix, then “,sc” is my shortcut, and “sc” is the spreadsheet calculator.

    • There isn't just the risk of a name clash between programs that you use. It's a hygiene problem: a clash that you don't know about, involving some program you don't use (or not directly).

      The system programs can potentially rely on each other, invoking each other in a way that relies on PATH searching, and not set PATH to a sane value when they are invoked. Your utility can accidentally shadow something and break the program whicc relies on it.

      In other words, setting PATH to point to ~/bin first breaks unhygienic programs which blindly inherit PATH --- which is pretty much all non-setuid programs in a Unix-like system!

      Setting PATH to point to your ~/bin last, on the other and, potentially breaks your programs when they call each other (in a way that relies on path searching), and are shadowed by new system programs. A fix for that is to to put ~/bin last, and ensure that all your programs refer to each other in a way that doesn't rely on PATH. E.g. prog is invoked as $bob_utils/prog.

    • Got it thanks -- that's what I was calling "namespacing" then yeah.

      Not a problem I've ever had, but I guess I like the solution if it's one you do often.

      Thanks for confirming.

  • As he pointed out, he’s also able to take advantage of tab completion this way, and he doesn’t risk getting the wrong command if his path is modified.

According to POSIX, variables that contain lower-case letters are for application use. If Debian (or whoever) introduces such variable names, they are being nonconforming.

For instance, my programs might be in /home/kaz/bin. Suppose I create a one-letter variable:

  k=/home/kaz/bin

Then /home/kaz/bin/foo can be run as

  $k/foo

Bash will complete on this. Firstly, $k[Tab] will add the missing slash to make $k/. Then if Tab is hit twice, the completions under /home/kaz/bin are shown.

Since k contains an absolute path, it does not rely on PATH searching.

The programs under $k/ can refer to each other using the $k/ notation, without relying on PATH.

The comma notation relies on PATH. When the ,foo script wants to invoke the ,bar script and just calls it ,bar args ... that relies on PATH containing the directory in which ,bar lives.

For interactive use, I'd use PATH anyway: put /home/kaz/bin at the end. Then if the system shadows one of my programs prog, I can just use ~/utils/prog or $k/prog to detour around the clashing system program. My programs themselves don't rely on PATH for calling each other, so they are immune to the shadowing, and since I added the new PATH element at the end, I haven't perpetrated any shadowing that would break system programs.

Many Lisp REPLs require you to prefix REPL metacommands with a comma. This helps distinguish between metacommands and variables to be evaluated, because the comma is the unquote operator to the Lisp reader, and is unlikely to occur in a Lisp expression outside a quasiquoted sexpr.

This is a great idea. I would have assumed by default, with no particular reason, that tools would choke at least on file names starting with, if not all of those containing, a comma, but a quick test with a few basic bash tools shows no issue.

I wonder (having never really grokked the latter) if it's productive to think of this as akin to a leader key in vim ….

> Red Hat never really worried me, because they packaged (comparatively) so little software.

Erm, nope:

    $ dnf repoquery -l $(dnf repoquery -f /usr/bin/\*) | grep ^/usr/bin | wc -l
    34989

  • I think the OP meant in comparison to Debian. Official Red Hat repositories have been way smaller than the official Debian repositories for as long as I can remember, back to the 90s. I know Fedora has a lot more packages though.

    • That's hardly a fair comparison, unless you can call up Debian on the phone and get 4 hour support for any of those binaries. Back in reality Fedora is the closest analog to Debian.

      1 reply →

The author has helpfully open-sourced the scripts as well, some of which are quite helpful like this one to convert dates to unix time and back: https://github.com/brandon-rhodes/homedir/blob/master/bin/%2...

Agree with the commit message; I've probably spent way too much time the past decade firing up a python prompt or using an online epoch converter to do this.

> And, best of all, thanks to the magic of tab-completion, it became very easy to browse my entire collection of commands.

This. I always forget the names of all these useful tools that I only use now and then.

Brrrr, such an ugly solution. If you want proof against future then you should use longer naming, maybe something that ends in <First name initial, Last name initial, Middle name initial, Underscore, my>. Allows to get better implementations of existing ones and having a fixed schema can help you in the future as your personal tools library grows.

Examples:

cat -> cat_uni_my (personal implementation of standard cat)

grep -> grep_uni_my (personal implementation of standard grep)

  • That’s not really easier to type though :)

    • maybe, but it's a lot easier to understand if you share your tools with other people. As for personal use, sure, you can do whatever you want, including using his comma style naming.

That's weird, because I use comma every time I type something in my shell (on Windows, not cmd.exe, but FAR). Why? In order to make sure that builtin ",time" is called, not "time.exe", because FAR Manager would try to run the executable under the PATH, instead of the command.

BTW I've long wanted to do sth like this:

Assume I have commands my_cat, my_grep, my_sort, my_send, and I want to use them in a pipe

with_prefix my_ | cat file | grep phrase | sort | send | end_with | cat

The last cat would be the system one.

I don't think it's possible with bash?

  • > I don't think it's possible with bash?

    No, pipes don't work like that. The closest I can think of is something like `(PATH=~/bin; cat file | grep phrase | sort | send) | cat`, where the custom commands don't have a prefix.

  • You could have a file with functions binding, for example, `grep` to `my_grep`, then `source` that file in a subshell:

       ( source with_my_prefix.sh
       cat file | grep phrase | sort | send | end_with | cat
       )

TL;DR Prefixing your custom commands/scripts with a comma, in order to avoid collision with present or future system commands.

Been doing it for years with a jj prefix instead, it is just under my index finger on the home row :-)

On my International English Magic Keyboard I'd use § for convenience though. Neat idea, works with aliases too.

Although this seems like a good idea, I wouldn't like typing an extra symbol. Maybe I'm just irrational.

Instead of prefixing my commands, I just search for a command in a manpage repo, cht.sh [0], and with my package manager (`dnf provides` for the DNF package manager). If nothing shows up, I'm probably safe. The process is easy to automate.

  • The problem is meant to deal with future conflicts as well as present ones, and re-checking on every update would be a pain. The more memorable and natural your aliases, the more likely they are to get clobbered later ….

  • Typing a comma is too hard, but that 4-step jerry-rig isn't?

    • It isn't "too hard" for me; it's just one of my irrational personal preferences. I don't claim that my solution is more efficient; I just don't like typing a leading comma and I think this "feels" more pleasant for me, and perhaps a few others.

  • There is also the other advantage pointed out in the article, in that typing a comma and hitting tab lists all his custom commands.

the dash character would also work.

  ▷ echo 'echo "this is a -test"' > ~/bin/-test
  ▷ chmod +x ~/bin/-test
  ▷ -test
  this is a -test

How is this ugliness a solution? How about just name the binaries properly - I'd rather just prefix my commands with ~/bin.me/<blah> and keep ~/bin out of my PATH, than futz with horrid looking names. Or, even better, just put my username in front of it .. "fit2rule_grep" ..

~/bin turns a luser write vuln into a luser arbitrary execution vuln. fight me

"Like many Unix users, I long ago created a ~/bin/ directory in my home directory"

No, this is my laptop - /usr/bin is the place for that. No, this is a simple server - /usr/bin is the place for that.

Perhaps I'm missing something after 23 odd years of using Unix systems including this Arch laptop.

  • /usr/bin is under the control of your package manager _ unless you're building and installing packages for all your adhoc scripts, aren't you worried about name collisions?

    • I know Arch's package manager, at least, will refuse to install a package if it would overwrite an existing file.

  • I keep ~/bin for easy version control/backups of my own scripts. I don't want to make a directory/repo for each script, and for getting them on PATH I can either add ~/bin to PATH or remember to run ln -s ~/bin/* /usr/bin/ after adding a script. Adding to PATH has saved me a few seconds of minor frustration at no cost.

  • Stuff in /usr/(bin|share|...) might get overwritten by system update or reinstall. A better choice is /usr/local/

  • I can't write to /usr without root, and I can write to home. I also personally like a clear delineation between things that are managed by the package manager and by myself.