6 ms·
Show HN: Cosh – concatenative command-line shell
- pjerem 4y agoIt's the same idea as Powershell, no ?
- tomhrr 4y agoYep, at least as far as working with structured data rather than streams of text is concerned. Apart from the syntax differences, this is generally much lighter weight, though, in that it doesn't have classes, in-depth system integration, or similar (not that those features are bad in Powershell).
- KMnO4 4y agoSeems interesting, but I’m already lost at the first example: lsr; [test m] grep; [f<; [data m] grep] map I’m guessing the lsr is a recursive ls, and presumably map is a HOF (functional) map. I know what grep means. So that means “test” and “data” are strings, and I have no idea what “m” is for. And “f<“ could be anything. Perhaps it’s more parseable to someone who speaks lisp, but I still think not having clear (simple) examples is a nonstarter for a project like this.
- tomhrr 4y agoThe 'sh' command that it corresponds to is above it: find . -iname '*test*' -print0 | xargs -0 grep data but possibly a bad assumption on my part that the mapping was clear. In any event, 'm' is for regex string matching, and 'f<' is for reading a file into a generator (basically an iterator over the lines in the file). It's a good point that more, simpler examples would help.
- ktpsns 4y agoThe examples in the README are really not the best. Anyway, given from the examples for me this reads as a language to write hacky onliners of code which are probably easy to write once but hard to read anytime after. One moment... we had such a language in the past: Perl! :-D Perl5 onliners were infamous for their expressive power but sometimes crazy to understand even if you thought you were fluent in perl ;-)
- tomhrr 4y ago> Anyway, given from the examples for me this reads as a language to write hacky onliners of code which are probably easy to write once but hard to read anytime after. There is definitely a 'write-only' angle to concatenative (postfix) languages that rely on a stack. I think this type of language/approach is uniquely well-suited to this use case, though, where the focus is interactive use, plus short programs that are not generally intended for distribution, since you get the most out of the advantages around conciseness, without incurring the costs that come with larger programs.
- silon42 4y agoWe have 2 now, perl and jq
- etatoby 4y agoEven after perusing jq's manual multiple times and having written several complex incantations, I still have no idea how to properly combine `|` and `.[]` except by trial and error, or why `select()` needs to be used inside `map(select(...))` Recently I needed to extract some data, and after fighting with jq and its manual for half an hour, I solved the problem in 30 seconds with node.js I appreciate the idea behind jq, but its language is horrible. Even XPath was easier and cleaner.
- AndyKluger 4y agoSome nice alternatives for querying JSON via CLI include jello, yamlpath, and dasel.
- bradknowles 4y agoDon't forget `gron`.
- brazzledazzle 4y agoWhich one do you think is best? And, if applicable, which one do you love but it’s not quite first place material yet?
- tsegratis 4y agoI love the premise. I've got be your market audience, but the examples are too hard for me: both sh & cosh I don't use `find` and I would have to look up `-0` Why does cosh use ; the syntax kinda looks like they're not needed?
- tomhrr 4y ago> but the examples are too hard for me: both sh & cosh Thanks, I'll look at adding some simpler examples. > I would have to look up `-0` The thing about '-0' is that it's not required in cosh, because you're dealing with proper values instead of text streams. The problem that '-0' (and '-print0') is addressing doesn't arise. > Why does cosh use ; the syntax kinda looks like they're not needed? ';' needs to be used to denote the previous string (token) as a function where that can't be determined from context. For example, if you type '1 2 +' and press enter, the shell will assume that because there's a function called '+', the intention is to run that function, but you could also enter '1 2 +;' (or '1 2 + ;') to get the same result. Whereas '1 2 + 1 2 + +' doesn't work, because the shell doesn't know if the first two '+' symbols are meant to be interpreted as function calls or just plain strings. The other place where it assumes that a function call is intended is at the end of an anonymous function, so `[1 2 +]` and [1 2 +;]` have the same effect.
- olodus 4y agoDon't listen to most of the people here. Perl? What are they talking about. It is a concatenative shell. Think forth. That said, the examples could be better explained just like you did here now. The examples are not bad but things like the f iterator probably needs some explaining. I really like the idea. A more simple shell language is something I've wanted. Either lisp or forth would work but the basic issue is that bash and the rest are so complicated and with so many special things you have to know. Doing anything other than most basic shell scripts is horrible.
- tomhrr 4y ago> That said, the examples could be better explained just like you did here now. The examples are not bad but things like the f iterator probably needs some explaining. Thanks, the readme has been expanded now so that it has better examples, and the full documentation (https://github.com/tomhrr/cosh/blob/main/doc/all.md https://github.com/tomhrr/cosh/blob/main/doc/all.md) is more clearly marked for those who are looking for more detail.
- yesenadam 4y agoIt appears to be extremely similar to Forth, surprisingly. The docs sections on Variables, Functions, Loops, at least, are all pretty much exactly Forth. the docs: https://github.com/tomhrr/cosh/blob/main/doc/all.md https://github.com/tomhrr/cosh/blob/main/doc/all.md
- cmrdporcupine 4y agoThat's specified right in the article title. The "concatenative" language family includes Forth, but also PostScript, Joy, etc. Languages in which expression reduction is expressed concatenatively via e.g. a stack, RPN syntax, etc. Consistent and powerful and terse, but IMHO hard to read. I think it's a great idea for a shell/script language, maybe, but not universally easily readable.
- yesenadam 4y ago> That's specified right in the article title. My point was that a lot of the grammar seems exactly the same as Forth's, and different to, say, Postscript's.
- cmrdporcupine 4y agoAh, ok, fair point
- rout39574 4y agoConsider JSON output formats, and jq as your swiss army knife between operations. The disadvantage of "first class values" is that now you need a type system to help determine what values can be used in what way, and it becomes complicated to use a data stream in a manner which was not anticipated when it was authored. If you keep the exchange format as close to plain text as possible, it's much more straightforward to do new things with it.
- recuter 4y agoI feel like somebody should mention Nushell. So, err, hey, did you hear about Nushell? You should check out Nushell: https://www.nushell.sh https://www.nushell.sh
- xwowsersx 4y agoI feel you missed the opportunity to say "So, nu, did you hear about Nushell?", 'nu' being the somewhat untranslatable Yiddish word for "Go on! Well? Come on!"
- waffletower 4y agoClosh is an interesting functional shell as well - https://github.com/dundalek/closh https://github.com/dundalek/closh While not an interactive shell, I find find babashka - https://babashka.org https://babashka.org to be elegant for scripting.
- etatoby 4y agoI'm very puzzled by this language. Why put the verbs at the end of the sentence, for instance? Was this shell inspired by Japanese or German?
- gpderetta 4y agoBecause that's the very definition of a concatenative language.
- JadeNB 4y agoI don't think that there's anything inherent about concatenative languages that forces them to be postfix. The Wikipedia definition (not authoritative, surely, but one we can all access) is: > A concatenative programming language is a point-free computer programming language in which all expressions denote functions, and the juxtaposition of expressions denotes function composition. As long as all functions are fixed arity—admittedly a serious limitation—there doesn't seem obviously to be any reason you couldn't write the function first (though of course it's fair to ask why you would want to).
- cyberbanjo 4y agoOm is a prefix concatenative language https://www.om-language.org/index.html https://www.om-language.org/index.html
- gpderetta 4y agoI associate concatenative languages with stack languages, which means that the postfix syntax is obvious. But as the sibling comment mentioned, that doesn't necessarily need to be the case.
- layer8 4y agoIt makes for strict left-to-right evaluation/execution.
- floatinglotus 4y agoIt reads like yoda said the command. And I don’t mean that in a good way.
- LorenDB 4y agoI find it interesting that, while this is marketed as "simpler" to work with data than bash or sh, over 50% of the examples have the sh/bash command shorter than the equivalent cosh command.
- jodrellblank 4y agoThe article says: > A small set of versatile primitives means that less needs to be remembered when compared with typical shells [...] though some commands may be longer as a result
- MobiusHorizons 4y agoThe elephant in the room for me is that > implemented as functions that return first-class values, as opposed to relying on executables that return text streams. This makes working with the results simpler Is explicitly disregarding several Unix philosophies, but not really discussing why the author believes those philosophies are wrong. It proceeds to produce code without the (at least in my view) nice properties of Unix shell style pipelines, namely the ability to compose them in novel ways due to a high compatibility between formats. I would welcome a discussion of how the Unix philosophies break down, or what they prevent. But I didn’t find that here.
- tomhrr 4y ago> Is explicitly disregarding several Unix philosophies, but not really discussing why the author believes those philosophies are wrong. I'm not sure I'd characterise these parts of the Unix philosophy as 'wrong'. For example, if you are writing a shell program for use by somebody else, then having that program work with text streams makes sense. The focus here is interactive use and short functions/programs for local use, though, which means that the text stream part of the philosophy becomes a less pressing consideration. > I would welcome a discussion of how the Unix philosophies break down, or what they prevent. But I didn’t find that here. At least as far as text streams go, the readme talks about awkward considerations like '-0' and '-print0', but more generally, when the command doesn't output a known format like XML or JSON, parsing the output can be fun (e.g. per https://stackoverflow.com/a/15643939 https://stackoverflow.com/a/15643939). Oftentimes the response is "the command has flags for getting the data that you want", but it's simpler (IMHO) not to build this sort of functionality into every command, and instead just have the shell support it more nicely, whether by providing a function that produces a first-class value (e.g. 'ls', 'ps' here) or by providing more generic parsing functions (e.g. 'split', 'splitr' here).
- Fnoord 4y agoThe problem is IMO a lack of a coherent flag to output such. If each CLI program would've a coherent flag, it would make the command line and scripting a tad easier. But with a decent command line history (or tool to parse such, such as history | fzf) its reasonably easy and quick to figure out the past.
- saeranv 4y agoI'm really intrigued by this, because I like postfix notation and would love to be able to work more with in. Unfortunately, I only somewhat understand the examples! Question: Does the postfix notation allow you to chain commands together that in bash would have to be nested in brackets, like actual postfix math? So for example, rather than the infix need of brackets to resolve ambiguity in this expression ((1 + 2) * 3) = 9, postfix just writes it like this: 1 2 + 3 * = 9.
- tomhrr 4y agoThanks, and yep, the postfix notation allows for chaining commands together without parentheses. For example: 1 2 +; 3 * (The semicolon is used to indicate that the previous string (token) is a function and should be executed. In some instances this is implicit, like when the last string (token) in a larger command (like the one above) maps to a function name, in which case it will be treated as a function call even when no semicolon appears after it.)