Hacker News new | past | comments | ask | show | jobs | submit login
Start all of your commands with a comma (2009) (rhodesmill.org)
253 points by Tomte on April 4, 2020 | hide | past | favorite | 89 comments



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.


Please cover your mouth when you cough.


Your solution requires shell support and is incompatible with previous code, while the author’s solution works today.

Who has the wrong solution now?


Software can be bad.


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.


If you are using absolute paths, I found this easier to get used to:

    hash -d b=/home/me/bin
Then you call foo as:

    ~b/foo
I have an array of these defined to my most used directories.


I believe hash -d and supsequent expansion of those paths only works in ZSH, which calls this "static named directories" (http://zsh.sourceforge.net/Doc/Release/Expansion.html#Static...).


Unfortunately, some bash completion scripts will expand $k to \$k…


That indicates they are broken. Completion scripts must not break basic completion features like completing shell variables.


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.


Touché. I didn't actually point out the difference as a point in favor of Debian; I can see the advantages of both approaches.


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.


  date -d @$1 +%Y-%m-%d


$ date -R Gets you very close with fewer characters


I mean, if you're not fixed on the output format, then date +%c.


Some time ago I wrote a simple tool to implement directory history in bash. Unfortunately I couldn't use 'cd<' and 'cd>' for obvious reasons, so I used 'cd^' and 'cd,' instead.


But bash already has pushd and popd


Umm, I wasn't aware.


> 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.


What's wrong with ls ~/bin?


Two keystrokes vs 9 (using shift with some keyboard layouts). Also, interaction with zsh or fish is better.


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.


FYI in bash there's somehow similar `command` built-in.

Say you have an alias that overrides `ls`. When you want to run original ls, you run `command ls`.


That's good tip to know! Thanks!

Wonder if you have /usr/bin/command - well gotta try it! :)


I believe `\ls` does the same thing.


Or, you know, fully-specified path:

    /bin/ls


When you override a bash built-in like `cd` with an alias, `command` is the only option.


Fair point.

Is there an alternate mechanism for invoking a shell's built-ins externally? Obviously for state-changing operations such as 'cd' that's of limited use.

   $SHELL -c '<commands>'
Comes to mind. Though likely bypassing initialisations might be useful.


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 :-)


Typing jj+tab gives me:

    jjdoc   jjs     jjtree
on Ubuntu 18.04


I just name all my shell scripts in all-caps. Nary a collision...


I hope you don't use APFS…


APFS can handle FOO and foo just fine, and I think only on macOS do you have to ask nicely that you'd like to have them not conflict, iOS and watchOS already do that by default. I have observed no problems with running a fully case sensitive macOS install.


Interesting! I seem to recall that not all to long ago a lot of things would completely break if you tried to use a case-sensitive filesystem.


I think Adobe or other entrenched bloatware might still break, but I had zero problems with it so far and I use a reasonable range of applications.


Nope. NetBSD...


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


§ is an ugly but very useful delimiter in csv-like files too. Almost never present as a regular character.


I’d never heard of that keyboard before. Is this something that’s handy for programming because it had extra keys?


No, I just chose it over US English for the L-shaped Enter key and over UK English because # was easier to access. You can see the layout differences here:

https://www.apple.com/uk/shop/product/MLA22B/A/magic-keyboar...


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.


He does that check once, when he's deciding on what to name it, not every time he runs the command.


This, plus I also said "Maybe I'm just irrational".


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


All my scripts are in one directory [0] that's added to the front of my $PATH [1]; listing files in it would be trivial.

The author's solution does seem much better; I just use my approach instead because I don't like the feeling of typing a leading comma :). I might switch to using a leading char sometime.

[0]: https://git.sr.ht/~seirdy/dotfiles/tree/master/Executables/s...

[1]: https://git.sr.ht/~seirdy/dotfiles/tree/master/startup.sh#L1...


the dash character would also work.

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


Why not just use shell aliases?


They are not real system commands; they can't be exec-ed.


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" ..


[flagged]


This is the second time tonight you've challenged the internet to fight you. I suggest meditation, a long walk, or some carefully selected drugs.


Meditation hurts my nose.


Oh, just like ~/.bash_profile would?


I’ll never get to sleep now.


Can't you just set permissions to rx but no write? Use sudo to update if any changes are necessary.


Who owns the directory?


"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.


/usr/local/bin?


Usr stands for universal system resource, look up the file hierarchy standard.


No, it's short for ‘user’.


More precisely 'users'. Every user can access it.


It started out as a separate drive for home directories and files that didn't fit on the first drive. cf. /usr/dmr (Dennis Ritchie), and /usr/ken (Ken Thompson).

https://blog.w1r3.net/2018/01/06/rob-landley-about-usr-split...


‘Users’ because that's where users' home directories were, like /home in Linux FHS or /Users in Mac OS. Then acquired overflow versions of bin et al. when the root disk filled up.




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: