Hugo Hacker News

Zx 3.0

another-dave 2021-08-16 14:08:18 +0000 UTC [ - ]

First impression is that I wouldn't go near it until it settles down a bit — it was on v1.7 in May and now on version 3 already.

Great that it's under active development, but changes to my scripts are infrequent and slow. I wouldn't want to be touching an old script on a server somewhere saying "How do I do X in ZX again?" and everything I find online is now for v15 while I'm still on v3.

Maybe if it had plans around a LTS version I'd take a look at that stage.

To be honest though I like doing things in bash. You can get pretty far & it's 100% portable. If something's too complicated for bash it's probably time it's not just a simple CLI script anymore, in my experience.

2021-08-16 17:23:40 +0000 UTC [ - ]

Stampo00 2021-08-16 18:35:44 +0000 UTC [ - ]

If you wrote your script against v1.7 and now they're on v3, you can still run your script. The v1.7 source and binary haven't disappeared. It's still available and work exactly the same as when you wrote your script.

SevenSigs 2021-08-16 15:49:56 +0000 UTC [ - ]

> First impression is that I wouldn't go near it until it settles down a bit — it was on v1.7 in May and now on version 3 already.

Would you feel better if they called version three v1.9 instead?

FinalBriefing 2021-08-16 15:59:37 +0000 UTC [ - ]

The major version bumps imply breaking changes. Two major versions within a few months implies I might have to refactor my code every couple of months to stay up to date, or face a buildup of tech debt if I want to take advantage of a new feature in the future.

If there are no breaking changes, then I would feel better if they called it v1.9.

staticassertion 2021-08-16 16:01:13 +0000 UTC [ - ]

Given that 3 and 1.9 have a completely different semantic meaning, they might.

SevenSigs 2021-08-17 01:30:27 +0000 UTC [ - ]

that depends on the developer(s).. didn't check in this case

tgsovlerkhgsel 2021-08-16 13:00:50 +0000 UTC [ - ]

As annoying as having to write "await" in front of everything is (probably should have a variant of $ that's synchronous), the ability to effortlessly implement parallelism is something that all other common scripting (and many "full") languages seem to lack.

Even Go, that prides itself on the good support for parallelism, fails once you actually want go get results back.

If this were paired with some way to also display the status/output of multiple commands in parallel, this would be the ultimate toolkit to write scripts.

If you look at apt, for example: Does it really have to wait for the last package to be downloaded before installing the first? Is there a good reason, on modern SSD-based computers, to not parallelize the installation of multiple packages that don't depend on each other?

q3k 2021-08-16 14:16:27 +0000 UTC [ - ]

> Even Go, that prides itself on the good support for parallelism, fails once you actually want go get results back.

It's doable if you're willing to build a very thin abstraction over whatever you're trying to parallelize keeping in mind all possible edgecases [1] and how you'd like to handle them.

A generic `run N things in parallel and collect their results` function would be nice, but would probably end up being quite unwieldy in comparison to just writing out a purpose-specific function for what you exactly need.

[1] - Error handling, timeouts/cancellation, maximum amount of processes running in parallel, wait-for-full-join vs. returning results as they appear, introspection of currently running subordinates, subordinate output streaming/buffering/logging, ... A lot of things to consider when you're trying to build something universal, but that are easy to solve/ignore when you're building something purpose-specific with known constraints.

tgsovlerkhgsel 2021-08-16 14:57:25 +0000 UTC [ - ]

That's the thing though... if the options are "write and test 30 lines of custom parallelism code to handle this stuff" or "everyone waits twice as long for their results", in practice most developers choose the latter.

Imagine if instead of that, you could do:

    foo, bar, []err := await getFoo(), getBar()
    if len(err) > 0 {
      return nil, nil, fmt.Errorf("Frobnication failed: %s", err)
    }
    return foo, bar, nil
Of course, JavaScript having exceptions as the main error-raising approach and `await` supporting them makes that a lot easier.

otabdeveloper4 2021-08-16 14:23:24 +0000 UTC [ - ]

Awaiting on every line is hardly parallelism.

tgsovlerkhgsel 2021-08-16 14:48:33 +0000 UTC [ - ]

The code in the main readme (https://github.com/google/zx) has an example of parallelism (the Promise.all line).

reddit_clone 2021-08-16 22:05:45 +0000 UTC [ - ]

Give Perl6/Raku a shot if you haven't yet.

IMO, it is pretty much the best-of-all-worlds language that is still accessible. (Meaning not exotic like Haskell or Erlang..)

The concurrency is beautifully painless.

rurban 2021-08-16 14:13:28 +0000 UTC [ - ]

using sh is usually preferred:

   somecmd & someothercmd & wait
runs the two commands in parallel and waits for both. no need for await. to run in serial replace & with && and skip the wait

striking 2021-08-16 16:53:15 +0000 UTC [ - ]

You lose the ability to know whether they succeeded or failed, though. Like most things given to you for free by the shell in shell scripting, it's only like halfway to a real solution.

(If you know how many subshells you started and won't get confused by which is which, you can use `wait -n && wait -n && ...` in bash)

MisterTea 2021-08-16 19:28:22 +0000 UTC [ - ]

Couldn't you redirect the stdout/error file descriptors to achieve the same thing?

tgsovlerkhgsel 2021-08-16 14:50:50 +0000 UTC [ - ]

Huh, neat, didn't know "wait". Thanks!

Still doesn't let you easily get the output of the two commands, but a good start.

10000truths 2021-08-16 15:46:35 +0000 UTC [ - ]

You can just use files as a temporary buffer:

    (/my/bg_producer1 > /shm/file1) &
    (/my/bg_producer2 > /shm/file2) &
    /my/longrunningfgjob
    wait
    (/my/consumer1 < /shm/file1) &
    (/my/consumer2 < /shm/file2) &
    wait

Siira 2021-08-16 14:46:48 +0000 UTC [ - ]

Take a look at GNU Parallel. It’s magnificent.

otabdeveloper4 2021-08-16 14:22:13 +0000 UTC [ - ]

> await await await await

Oh yeah, right, because the first thing that comes to mind when writing bash scripts is "I sure wish there was more 'await' noise in all this code!"

Anyways: 'async' in the Python and Javascript sense was a mistake, future generations will think we were insane to adopt it.

https://journal.stuffwithstuff.com/2015/02/01/what-color-is-...

Vinnl 2021-08-16 15:08:06 +0000 UTC [ - ]

I haven't looked into Zx yet, but at least for JavaScript that "what color is your function" article also applied before they added the syntactic sugar. If your function was async via a direct callback then the calling function would have to accept a callback too.

eyelidlessness 2021-08-16 22:07:33 +0000 UTC [ - ]

Given Promises and callbacks have always been pervasive in JS—that it’s always been heavily asynchronous—I can’t imagine thinking async/await was a mistake. It’s a drastic ergonomic improvement over both, and it also drastically improves debugging and error stacks.

Adding it to a language where IO is typically blocking with other ergonomic concurrency mechanisms, that I can imagine being somewhat controversial.

It would be good if async weren’t infectious, but as a sibling comment said that was already the case with Promises and callbacks.

It would maybe also be better if concurrency was the default behavior and keeping a reference to a promise was the explicit syntax, but I could see downsides to that. It potentially hides/encourages excessive use of expensive calls. And implicit concurrency is a potential source of many bugs.

laurent123456 2021-08-16 15:38:10 +0000 UTC [ - ]

Those are small examples but for more complex scripts I expect you'd mostly have synchronous code, for example to process strings, validate input, etc. and the "await" will become the exception rather than the norm.

tusharsadhwani 2021-08-16 18:17:56 +0000 UTC [ - ]

Shameless plug; might wanna look into zxpy :)

cfeliped 2021-08-16 10:10:32 +0000 UTC [ - ]

In my first job I gave a try at using Python for scripts.

It was a terrible idea, as I now had 3 problems instead of 1:

1 - Writing scripts, plus:

2 - Installing Python in every host that needed to run those scripts

3 - Maintaining Python and the necessary dependencies up to date in each host / container.

(2) and (3) are trivial when done just once in your own computer, but end up being a huge time sink for larger heterogeneous environments with (possibly) network and security barriers. Moreover, if you are using containers, installing Python will make images unecessarily large.

Granted, I'm not a JS person, but I imagine one will have the same issues.

Even though bash has its shortcomings, I really appreciate how low maintenance it is as long as you keep scripts small and sane.

qalmakka 2021-08-16 10:23:29 +0000 UTC [ - ]

That's why Perl is my go-to choice for glue scripts. It's almost always installed by default, it has stayed consistent for decades without any breaking changes, its regex support is by far the best around, and its almost as good as the shell at gluing commands together.

nyanpasu64 2021-08-16 11:01:50 +0000 UTC [ - ]

I'm less likely to have Perl installed than Python on Windows, where I sometimes want my scripts to run as well.

qalmakka 2021-08-16 14:32:02 +0000 UTC [ - ]

It's also unlikely you have Python installed on Windows though, and there's a non-insignificant change that's an old or random version (probably even Python 2). You can't rely on anything on Windows, so you're definitely going to also install a runtime from Chocolatey or similar.

thatwasunusual 2021-08-16 13:52:24 +0000 UTC [ - ]

> That's why Perl is my go-to choice for glue scripts. It's almost always installed by default

My first thought was related to this as well: Perl is _always_ installed, and based on Python's popularity (compared to Perl, at least), I'd assume that Python also was installed by default?

That's an honest question, btw: I use Perl quite a lot, Python not so much (at all). :)

cfeliped 2021-08-16 14:09:39 +0000 UTC [ - ]

Assuming Python or Perl are installed by default in any server is an invite to a world of pain. At least that's my anecdotal experience.

qalmakka 2021-08-16 14:34:15 +0000 UTC [ - ]

I've seen instances of some Unix systems not having Perl installed, but that's very rare. Basically everything directly or indirectly depends on Perl, so you really have to run your scripts on a minimal install of RHEL of FreeBSD with 0 ports in order to get into such a situation.

mst 2021-08-16 17:02:27 +0000 UTC [ - ]

And for that situation you can always break out http://p3rl.org/App::staticperl.

Plus of course if you want to use (pure perl) cpan dependencies I wrote http://p3rl.org/App::FatPacker and http://p3rl.org/Object::Remote to make that easier.

thatwasunusual 2021-08-17 02:50:24 +0000 UTC [ - ]

> And for that situation you can always break out http://p3rl.org/App::staticperl.

Why do you link to p3rl.org? And, more importantly, why do you link to something that doesn't exist?

cfeliped 2021-08-16 17:29:23 +0000 UTC [ - ]

Many container base images won't have perl by default (e.g: alpine).

For servers it's less common, but enterprise systems never cease to amuse me.

qalmakka 2021-08-19 09:27:17 +0000 UTC [ - ]

Most container base images are often so barebone you can't really count on them containing anything. For instance, on an Alpine image you can't count on bash.

thatwasunusual 2021-08-17 02:47:09 +0000 UTC [ - ]

Why?

andrewl-hn 2021-08-16 10:26:48 +0000 UTC [ - ]

JS is marginally better than Python for this, because tools for runtime and package version management are better for Node than for Python (proper lockfiles, local package folders, npm bundled with Node for installation, etc.).

Still, zx isn't as nice as Ruby, which has backticks for calling shell as part of the language. So, you don't have to have a separate package installed, just the ruby runtine.

But Perl is even better! Just like Ruby, it comes with backtick shell execution build-in, but unlike Ruby Perl is ubiquitous and is pretty strict about backward compatibility. So, your scripts will just run on all machines you have, no matter what distro you use and how old the machine is (within reason).

ptx 2021-08-16 16:30:07 +0000 UTC [ - ]

Zx seems[1] to take advantage of the way template literals work in JS to do proper shell escaping of the parameters to prevent command injection. Is that handled by the Ruby and Perl backtick syntax as well?

[1] https://github.com/google/zx/blob/3.0.0/test.mjs#L30-L33

gravypod 2021-08-16 13:11:17 +0000 UTC [ - ]

Luckily today you can side step many of these issues. You can compile a copy of python + modules + pex into a single file with some open source tooling and get a flat file you just need to copy to your hosts.

sumtechguy 2021-08-16 14:46:03 +0000 UTC [ - ]

Bash just sort happened to be the lowest common denominator in most unix style environments. Because it just sorta ended up being the default. Unix ended up being this different thing where each distro seems to be kind of unique. Then on top of that they are very easy to customize. So while one distro you can assume a particular python level the next disto python is totally optional. Mix in containers and docker images and you have a new level of 'what may or may not be there'. Ah but you may say 'oh just use tech XYZ' that may or may not have the exact same issue as using python in its place. So either 'deal with it' and install what is needed and keep it up to date. Or 'play the LCD game' you use only the bare min and hope you can build something useful enough in bash when another lang may be more appropriate.

hulitu 2021-08-16 16:02:13 +0000 UTC [ - ]

I thought that was sh (i.e. bourne shell). As far as i remember bash is not the default shell on a lot of unices.

cfeliped 2021-08-16 17:31:30 +0000 UTC [ - ]

My understanding is that sh is a specification, not an implementation.

Most images will either have bash or ash installed. ash, being lightweight, is the choice of alpine and related distros.

asveikau 2021-08-16 19:32:28 +0000 UTC [ - ]

This is a bit of a Linux specific view of the universe. Yes posix has a standard for how sh should work. But there were specific implementations of sh, and you would get those on commercial Unix or *BSD.

Later shells came in and filled some gaps. OpenBSD still has ksh by default. Linux distros had bash as their /bin/sh.

cfeliped 2021-08-16 21:25:35 +0000 UTC [ - ]

I didn't know that. Thank you for the explanation!

2021-08-16 10:24:00 +0000 UTC [ - ]

kjgkjhfkjf 2021-08-16 09:45:07 +0000 UTC [ - ]

I'm having a hard time believing that Google uses this much internally. Is github.com/google just a place where Googlers can put personal projects to get additional exposure?

Dobbs 2021-08-16 09:53:08 +0000 UTC [ - ]

I was under the impression that `github.com/google` was largely projects being worked on by googlers where the code is owned by google, but the code isn't always being used by google. Say 20% time work, side projects built using google resources, etc.

tym0 2021-08-16 09:53:04 +0000 UTC [ - ]

The copyright of the thing Googlers build on their oswn time are usually owned by Google and so it ends up on the Google org if they want it on GitHub. They usually have a disclaimer like "this is not a official Google product..."

travelbuffoon 2021-08-16 11:13:50 +0000 UTC [ - ]

Yup - or at least that’s what Google tells their employees. Want to publish something - you’d better get permission, and stick the Google name on it. And based on my limited understanding of the US contracts, is also true in practice.

There are some exceptions depending on local laws and contracts though, so it’s only mostly and not always true.

codewiz 2021-08-16 10:24:23 +0000 UTC [ - ]

This isn't correct: if a Googler writes some code from scratch, which is unrelated to their work, on their personal time, and using their personal laptop... then it's definitely not owned by Google.

There could be gray areas where code ownership could be disputed, but in general your employer owns only the intellectual property it paid for.

Source: I'm a Googler (until next month).

marcyb5st 2021-08-16 11:44:46 +0000 UTC [ - ]

Not true. You need explicit permission (there is a process for obtaining it, and it is very lightweight as I've done it myself). The general idea is that you get permission without much hassle if you develop something that doesn't compete with Google. You need to argue your case otherwise.

Source: I'm a Googler that went through the process before.

Edit #1 for all Googlers reading this: search "IARC" internally and you should land on the proper page to kickstart the process.

tgsovlerkhgsel 2021-08-16 12:46:23 +0000 UTC [ - ]

Many companies make claims over their employees' intellectual property. How much of a claim they actually have legally is a different question, which depends on the country (and sometimes state) where the employee works, and companies routinely attempt to claim more than they legally can.

Compare e.g. https://thebusinessprofessor.com/en_US/property-law/californ...

I bet Google lacks the copyright for many of the projects they claim.

marcyb5st 2021-08-16 12:54:39 +0000 UTC [ - ]

Maybe true, but I am unwilling to try my luck. I mean, the process I mentioned above takes 30 minutes [1] if it's clear you aren't competing with Google and so I don't see a major issue about playing it safe and have written consent to develop your idea/project.

[1] you fill a form with the general idea description, you explain succinctly why it doesn't compete to any Google product, and you acknowledge you won't use Google time and resources to develop it. Then a committee reviews it and in ~1 week you get your approval or request for more details.

q3k 2021-08-16 13:07:41 +0000 UTC [ - ]

It takes maybe 30 minutes to fill out, but the O(days) approval latency is what absolutely killed me. No way to do impromptu commits to random non-Google-license-approved projects, no way to hack together something with friends over a beer, no way to quickly bash together a proof of concept and release it the same evening.

It might work for people who chisel away at their own long-term one-person pet projects, but breaks down if you're used to quickly hacking away collaboratively in various groups. Especially if you're an active member of a hackerspace.

goohle 2021-08-16 13:11:19 +0000 UTC [ - ]

Many countries have a "formula" (legal definition) for a "contract", which include fair exchange of something for something else, e.g. time and labor for money. If Google forces their developers to work for free (labor for nothing), then it fails to meet legal definition of the contract.

IMHO, such "forced labor for free" is a form of slavery. Slavery is forbidden by law.

If a developer want to publish his project under Google brand, then exchange may be considered as fair (project code for Google branding).

q3k 2021-08-16 12:48:48 +0000 UTC [ - ]

> I bet Google lacks the copyright for many of the projects they claim.

Good luck taking Google to court.

kyrra 2021-08-16 12:28:44 +0000 UTC [ - ]

Btw, Google actually publishes this documentation externally.

https://opensource.google/docs/releasing/

q3k 2021-08-16 12:32:18 +0000 UTC [ - ]

They removed the `go/iarc` mirror recently, now seemingly only available on the wayback machine: https://web.archive.org/web/20210710210932/https://opensourc...

kyrra 2021-08-16 12:35:50 +0000 UTC [ - ]

Well that interesting. Thanks for pointing that out. Wonder why they did that.

marcyb5st 2021-08-16 12:58:25 +0000 UTC [ - ]

Thanks, I didn't know this. I thought it was only internal stuff.

codewiz 2021-08-18 06:38:37 +0000 UTC [ - ]

The IARC process is only necessary when Google might own copyright in the first place (those gray areas I mentioned earlier).

I went through the IARC process 2 years ago for a startup I was about to found in Tokyo, and obtaining clearance was easy, as you say. It's an extra precaution to avoid future litigation, but not legally required if you keep your personal coding activity clearly and provably separate from your work activity.

geofft 2021-08-16 13:25:13 +0000 UTC [ - ]

Double-check your employment contract. The offer I received (and declined, primarily for other reasons but this was on the list) in 2017 clearly stated that it had to be unrelated to any of Google's work as a whole, and in fact to Google's actual or anticipated work - not just to the employee's assigned work.

sneak 2021-08-16 12:03:44 +0000 UTC [ - ]

There is very little code that a Googler could write that is unrelated to their employer’s business. You’re almost certainly going to need an explicit carve-out, as other Googlers in the thread have pointed out.

travelbuffoon 2021-08-16 12:48:51 +0000 UTC [ - ]

There’s a difference between: unrelated to your job, and unrelated to the business as a whole.

In some locations, employers can’t claim copyright on works unrelated to your current role.

geofft 2021-08-16 13:27:05 +0000 UTC [ - ]

In many locations they can. I paid my own lawyers to review a Google NYC job offer and they said, yes, Google can enforce this clause.

(Obviously this is not legal advice, talk to your own layers, etc.)

wokwokwok 2021-08-16 10:47:24 +0000 UTC [ - ]

Are you sure?

Not in the “haha, yes of course”, in the “I’ve spoken to HR and have it writing” kind of way.

I’ve heard this is not true from others, it is simply true in certain geographical regions where local laws override the contract you signed.

mrgriscom 2021-08-16 11:06:38 +0000 UTC [ - ]

"The provisions of this Agreement requiring disclosure and assignment of Inventions to Google do not apply to any invention that I have developed entirely on my own time without using any of Google Property (as defined below) or Google Confidential Information, except for those inventions that either (i) relate at the time of conception or reduction to practice of the invention to Google’s business, or actual or demonstrably anticipated research or development of Google or (ii) result from any work or services that I performed for Google."

q3k 2021-08-16 11:36:38 +0000 UTC [ - ]

> (i) relate at the time of conception or reduction to practice of the invention to Google’s business, or actual or demonstrably anticipated research or development of Google

That's the catch. Not related to what _you_ do at Google, but related to _anything_ that Google does. Pretty much all the stuff I wanted to work on in my spare time while employed at Google could be seen as related to Google's business/research, as Google does a lot of things. And that's how Google seems to read this too, considering how the Open Sourcing documentation [1] is written.

[1] - https://web.archive.org/web/20210710210932/https://opensourc... “As part of your employment agreement, Google most likely owns intellectual property (IP) you create while at the company. Because Google’s business interests are so wide and varied, this likely applies to any personal project you have. That includes new development on personal projects you created prior to employment at Google.”

inshadows 2021-08-16 14:25:08 +0000 UTC [ - ]

OK. So the things under google GitHub organization are personal projects for which googlers didn't bother to get the permission?

skybrian 2021-08-16 15:20:35 +0000 UTC [ - ]

Often they are not entirely personal in that they wrote the code using 20% time (so this is code paid for by Google) and use them as part of their job and/or make them available to other users internally. So Zx might be used inside Google somewhere.

Since they started out owned by Google, you need permission to open source them.

But how much company support they have and how popular they are varies.

tyingq 2021-08-16 12:55:19 +0000 UTC [ - ]

I suppose it's easy to poke fun at combining the "best" of shell scripting and JS. But, the examples of using await() with child processes and pipes are pretty nice, and less verbose than the Perl or Python equivalents. It does seem well designed for anything where you're orchestrating parallel runs of commands.

thatwasunusual 2021-08-16 13:50:09 +0000 UTC [ - ]

For Perl, there is now Future::AsyncAwait.[0] Mojolicius has already adopted it, so things are moving forward at the speed of the magnetic poles shift. :)

[0] https://metacpan.org/pod/Future::AsyncAwait

mst 2021-08-16 17:08:59 +0000 UTC [ - ]

Plus while Mojolicious' support for running external processes is extremely limited because it's not really a goal of the project, http://p3rl.org/IO::Async::Process (by the author of the async/await system) is a gloriously complete interface and you can run Mojo::IOLoop and IO::Async::Loop code in the same process just fine.

maga 2021-08-16 08:37:52 +0000 UTC [ - ]

searchableguy 2021-08-16 10:04:38 +0000 UTC [ - ]

https://deno.land/x/dzx@0.2.4

Here is a more full fleded version.

SahAssar 2021-08-16 09:03:42 +0000 UTC [ - ]

That doesn't quote/escape arguments and with zx you can do the shebang so you don't need the import but implementing that in deno shouldn't be too hard I think.

satyanash 2021-08-16 09:32:08 +0000 UTC [ - ]

I personally find Ruby's built-in shell features more ergonomic:

    `cat package.json | grep name`

    branch = `git branch --show-current`
    `dep deploy --branch=#{branch}` if $?.success?

    [
      "sleep 1; echo 1",
      "sleep 2; echo 2",
      "sleep 3; echo 3",
    ].map { |cmd| Thread.new { %x(cmd) } }.each(&:join)

    name = 'foo bar'
    `mkdir /tmp/#{name}` if $?.success?

jitl 2021-08-16 12:39:39 +0000 UTC [ - ]

What I don’t like about backticks in Ruby is that they “ignore” errors in commands you run. It’s up to the program author to remember to check $? for the last executed command’s exit status. And guess how many times the average Ruby script using this feature implements error handling? Usually it’s totally forgotten.

To be safe, abstractions that make it easy to shell out must also:

- escape all variable interpolations by default using “shellwords” or similar.

- throw exceptions on error by default.

Backticks in Ruby are very easy to use, but aren’t safe.

dvogel 2021-08-16 13:18:39 +0000 UTC [ - ]

I agree that people often don't treat the exit code the way they should when using the backticks. However there's better options in the ruby stdlib too, like `system` and `spawn` and `popen`. Using the other methods allows you to also sidestep the shell if you know the arguments you want to pass.

ilyash 2021-08-16 15:33:27 +0000 UTC [ - ]

In that case, welcome to Next Generation Shell (I'm the author), which actually cares about errors when running external programs. Yes, I mean much more than naive "non-zero is error" because that's just not true in many cases.

https://ilya-sher.org/2017/01/28/ngs-unique-features-exit-co...

hulitu 2021-08-16 16:07:01 +0000 UTC [ - ]

I do not want to sound like an oldtimer but even command.com had "if %errorlevel%"

eatonphil 2021-08-16 12:41:58 +0000 UTC [ - ]

Ruby noob, but surely there's a way to metaprogram and change this to default to throw on non-zero exit?

chubot 2021-08-16 12:14:23 +0000 UTC [ - ]

How do you do shell escaping of #{name} if it comes from user input?

pornel 2021-08-16 14:55:23 +0000 UTC [ - ]

The unnecessary "from user input" qualification is why spaces are kryptonite for most shell-based tools.

It doesn't matter where input comes from. Input needs to be escaped for the context it's used in, period. Non-exploitable doesn't mean it's correct.

antifa 2021-08-17 15:47:54 +0000 UTC [ - ]

Crystal does this, too.

eurekin 2021-08-16 11:53:41 +0000 UTC [ - ]

Does this carry over to jruby as well?

azkae 2021-08-16 12:52:25 +0000 UTC [ - ]

Somewhat related, if you are looking to do scripts in Python you should take a look at `sh`:

  import sh
  print(sh.ifconfig("eth0"))
https://amoffat.github.io/sh/

ahaferburg 2021-08-17 10:36:36 +0000 UTC [ - ]

https://amoffat.github.io/sh/sections/faq.html

> Will Windows be supported?

> There are no plans to support Windows.

ducktective 2021-08-16 12:57:06 +0000 UTC [ - ]

Is this the ergonomic `subprocess.Popen` alternative?

azkae 2021-08-16 12:59:14 +0000 UTC [ - ]

Yes this wraps subprocess.Popen in a nice API.

jeswin 2021-08-16 13:06:58 +0000 UTC [ - ]

Shameless plug:

If you want the exact opposite of this (that is, to use JS from the shell), try https://bashojs.org

For example:

  curl 'https://api.openweathermap.org/data/2.5/weather?q=Bangalore&appid=2a125de83c277f4ce0ace5ed482f22b9' | basho --json -j 'x.weather[0].description + ", feels like: " + Math.round(10 * (x.main.feels_like - 273.15))/10 + "°C"'

miohtama 2021-08-16 08:26:59 +0000 UTC [ - ]

Zx is good if JavaScript is only language you know. If you have ability to program or learn other programming languages, Python with packages like Shell and Plumbum might be better choices for shell scripting tasks that outgrow shell.

- Python code with Shell is easier to read ana write

- No nees to carry async/await keywords thru the code

- Powerful plain text manipulation in the stdlib

https://pypi.org/project/python-shell/

https://plumbum.readthedocs.io/en/latest/

dogma1138 2021-08-16 08:37:04 +0000 UTC [ - ]

Powershell is also available for Linux these days, and well Powershell is awesome.

Not sure how I feel about needing Node.JS to run shell scripts…

SahAssar 2021-08-16 09:05:21 +0000 UTC [ - ]

> Python code with Shell is easier to read and write

That is pretty subjective

miohtama 2021-08-16 10:00:28 +0000 UTC [ - ]

Yes. I started programming in JavaScript in 1999 and Python in 2003, so it is my subjective opinion based on mastering the both languages. There are some factual and objevtive features making Python syntax more friendly, but it is a worth of a blog post to explore. And in the end there is no point, as JavaScript maximalists would not care.

alexghr 2021-08-16 08:38:11 +0000 UTC [ - ]

Maybe, but the main advantage of `zx` (at least for me) is that I don't have to manage another language environment. I can keep everything contained within Node :)

dogma1138 2021-08-16 08:42:04 +0000 UTC [ - ]

The problem is Node, especially all the packages that you’ll end up using under the hood, it’s seems quite risky especially if you don’t have super tight control over your Node SBOM.

Would be a bit more interesting to me if it was a JS shell built from the ground up without the entire mess of the Node package dependency baggage.

ptx 2021-08-16 16:39:42 +0000 UTC [ - ]

There's always WSH if you're on Windows and will settle for ECMAScript 3. No external dependencies or runtime needed.

alexghr 2021-08-16 08:48:16 +0000 UTC [ - ]

While I agree that Node's ecosystem is not the best, it's what we have in the frontend world.

If you're working on a Node-based service or React app, you already have to deal with Node and its package ecosystem. Adding a couple of extra MB (or even KB, depending on package reuse) on top of your existing chain of dependencies is a tiny con to the huge benefit of not having to do logic in Bash :)

dogma1138 2021-08-16 10:15:29 +0000 UTC [ - ]

The problem is that you don’t always know what is actually being executed, shell scripting is risky as it is without the rabbit hole that is the Node dependencies system.

arve0 2021-08-16 21:14:26 +0000 UTC [ - ]

zx has a small dependency tree, 12 packages marked as "@types" and 36 regular packages[0].

If you are fluent in Node, it should be easy to avoid further dependencies.

0: https://arve0.github.io/npm-download-size/#zx

mikevm 2021-08-16 09:21:12 +0000 UTC [ - ]

What is there to manage? Python comes built-in with pretty much every distro, and you only have to install one package.

wdroz 2021-08-16 12:23:38 +0000 UTC [ - ]

There is also xonsh[0] if you want an similar experience to zx to mix bash and python.

[0] -- https://github.com/xonsh/xonsh

IshKebab 2021-08-16 09:12:24 +0000 UTC [ - ]

Maybe but Python is sloooow and its type annotation situation is pretty poor.

I would recommend using Deno. It has the following advantages:

* Uses Typescript which gives you a great static typing system.

* Runs via V8 so it's about a million times faster than Python.

* Single statically linked binary with no project setup files required (package.json/dependencies.txt) makes it about a million times easier to deploy than either Node or Python. Especially on Windows.

* You can still use third party libraries even without a project file and you get IDE integration.

It's the clear winner at this point. Someone has even made a version of zx for it:

https://deno.land/x/zx_deno@1.2.2

tcbasche 2021-08-16 09:21:16 +0000 UTC [ - ]

I’ve found Python is just fine performance-wise for CLI tools. What bad experiences have you had with it? I’ve mostly used click.

IshKebab 2021-08-16 13:24:25 +0000 UTC [ - ]

Startup time is very slow. I just tested on my system and cold startup was 1 second (!) and hot 180ms. Vs 80ms and 64ms for Node.

Also it obviously depends what your CLI tool is doing. Just because something is a CLI tool doesn't mean it doesn't do much stuff and therefore performance doesn't matter.

For example Scons is a CLI tool. It's a build system written in Python. Everybody abandoned it because it was dog slow.

Mercurial is a CLI tool. It's a VCS written in Python. Most people have abandoned it partly because it is slow (and partly because Github exists).

You can read about Mercurial's troubles with Python performance here:

https://www.mercurial-scm.org/wiki/OxidationPlan

> Performance is a significant pain point with Python. There are multiple facets to the performance problem:

> * Startup overhead

> * General performance overhead compared to native code

> * GIL interfering with parallel execution

> It takes several dozen milliseconds to start a Python interpreter and load the Mercurial Python modules. If you have many extensions loaded, it could take well over 100ms just to effectively get to a Mercurial command's main function. Reports of over 250ms are known. While the command itself may complete in mere milliseconds, Python overhead has already made hg seem non-instantaneous to end-users.

miohtama 2021-08-16 13:42:08 +0000 UTC [ - ]

How much difference does 180 ms vs. 64 ms make for your use case?

IshKebab 2021-08-16 18:14:06 +0000 UTC [ - ]

It is definitely noticeable even when you run a command once. But it really becomes a problem when your command is run lots of times as part of some other system.

For example if you're using Python to process a lot of files via Make (something my work's build system does unfortunately) then it can end up costing 10s of seconds which is kind of insane.

mst 2021-08-16 17:14:31 +0000 UTC [ - ]

In scripts designed to be run directly at a bash prompt by humans, the difference would absolutely be noticeable.

watermelon0 2021-08-16 12:43:57 +0000 UTC [ - ]

Python interpreter by itself is fast, it spawns in a few milliseconds, but it can slow to a crawl if you need libraries, and easily take a few seconds.

However, situation is similar with nodejs.

gizdan 2021-08-16 08:32:35 +0000 UTC [ - ]

Wow, plumbum, despite it's unfortunate name, looks awesome. I will definitely try it next time I write a script.

philsnow 2021-08-16 08:42:31 +0000 UTC [ - ]

how is the name unfortunate? from the site:

> Plumbum (Latin for lead, which was used to create pipes back in the day)

gizdan 2021-08-16 14:24:20 +0000 UTC [ - ]

That's fair. My Latin is non-existent, and I clearly was too eager to look at example source instead of reading the description. I'll take my criticism and walk away.

marcusramberg 2021-08-16 09:46:40 +0000 UTC [ - ]

And yet it sounds like a thicc ass.

mst 2021-08-16 17:12:40 +0000 UTC [ - ]

I confess to being quite amazed that you saw an innuendo somewhere I didn't.

dogma1138 2021-08-16 10:52:20 +0000 UTC [ - ]

Yes, but the name choice was quite intentional and probably giggle inducing. This is about as toilet humor as it can get.

bovermyer 2021-08-16 14:27:34 +0000 UTC [ - ]

I wonder if your comment says more about how you choose to see the name rather than any inherent meaning.

Personally, I only see it as the old name for lead. Interesting to see how others are wired.

FroshKiller 2021-08-16 11:30:51 +0000 UTC [ - ]

According to the Classical Latin pronunciation I learned in school, this is "ploom-boom" rather than "plum-bum."

mst 2021-08-16 17:13:22 +0000 UTC [ - ]

I guess if you've never learned about the word 'plumbing' before?

hnarn 2021-08-16 15:46:03 +0000 UTC [ - ]

> Bash is great, but when it comes to writing scripts, people usually choose a more convenient programming language. JavaScript is a perfect choice

um… what?

FinalBriefing 2021-08-16 15:58:38 +0000 UTC [ - ]

It is _a_ perfect choice.

I know a bit of bash, but I'm always looking up how to do things I know are simple in JS. I would love to be able to write scripts in JS because I'm faster with it, and I find it easier to read.

gbear0 2021-08-16 17:45:08 +0000 UTC [ - ]

in case anyone is looking to do this, it's as easy as doing the following

  #!/usr/bin/env node
  console.log("Hello World!");

thex10 2021-08-16 16:11:31 +0000 UTC [ - ]

yeah same. As a front-end webdev who writes JS frequently, I've _never_ written shell scripts and thought "Wow, I'd really rather use JavaScript for this"!

Not saying it doesn't happen, just that it hasn't been my experience.

lloydatkinson 2021-08-16 17:03:30 +0000 UTC [ - ]

You’ve never written a bash script and needed to parse, format, concat lots of strings? What about arrays of strings? All of which is easier in just about any modern language.

kakuri 2021-08-16 18:00:38 +0000 UTC [ - ]

As a front-end dev who works with JS all the time and never writes shell scripts, every time I have to deal with shell scripts I think "I'd really rather use JS for this".

SCLeo 2021-08-16 18:04:34 +0000 UTC [ - ]

I am also a frontend dev. My experience has been completely opposite from yours. Node.js is my go-to tool for writing automation scripts.

I think these are some reasons why our mileages differ:

- I need my scripts to work in both Windows and Linux.

- I am not very experienced with bash or other shell.

- Most of my "automation work" only involves reading text from a file, transform it, and write to another file. (Generating SQL commands, doing stats about town names, etc.)

shell0x 2021-08-17 00:44:26 +0000 UTC [ - ]

I have never seen anyone using Javascript for scripting. Never. It's perfectly fine for app dev, but definitely not for running scripts on a server.

I came across Bash, Powershell, Ruby, Python, Go, Rust, Perl, but JS?

soheil 2021-08-16 15:58:49 +0000 UTC [ - ]

What is the nature of your outrage exactly? Bash is very difficult as a language to write code in. JS is very familiar to a lot of developers and its syntax is orders of magnitude easier to understand than Bash.

runawaybottle 2021-08-16 16:04:24 +0000 UTC [ - ]

The prejudice against JS developers is that they are seen as low class janitorial code monkeys by ‘real programmers’. It hurts these people even more because the language just succeeds and succeeds despite all the hate.

xemdetia 2021-08-16 16:30:27 +0000 UTC [ - ]

I would say that it's more that Bash is good at something and JavaScript is good at other things and just because they are technically scripting languages doesn't mean that they are naturally a good fit in each other's domains. The README's comment tends to point towards an idea that all languages that can write scripts are equally interchangeable and of all choices JavaScript is the perfect choice. To people that are working on a variety of scripts in numerous languages who all have individual advantages and disadvantages, it comes off as nonsense.

soheil 2021-08-16 16:53:48 +0000 UTC [ - ]

I think definitely there are better alternatives to JS in command line world like python but if someone decided to use something other than bash as a programming language that’s a win in my book. It has its place for basic scripts and general command line trickery but anything beyond that is using a hammer to do brain surgery.

egeozcan 2021-08-16 17:40:20 +0000 UTC [ - ]

I do think JS would be much better than python. It's more to do with familiarity.

shomyo 2021-08-16 17:26:25 +0000 UTC [ - ]

js kids thse days.

mikevm 2021-08-16 09:16:55 +0000 UTC [ - ]

Ugh, typing `await` for every command is terrible. JavaScript's async-by-default model is clearly not a good fit for this use case.

lucideer 2021-08-16 10:00:59 +0000 UTC [ - ]

Not sure what this comment means. Javascript has no "async-by-default" model.

The author of this library has chosen to make the "$" function they provide async; this isn't a JS design feature or limitation, it's just the lib author's choice.

Too 2021-08-16 14:04:46 +0000 UTC [ - ]

I think the idea is that the majority of the script will be written in pure JS, with only occasional calls out to subprocesses, so “every command” is far from every line.

You frequently see the same mental mismatch when shell-scripters try to use Python, and complain how hard it is to pipe with POpen, instead of using the built in string processing features.

lhnz 2021-08-16 10:59:11 +0000 UTC [ - ]

I wonder if they could use some kind of magic to create synchronous versions of all async APIs (e.g. https://giuseppegurgone.com/synchronizing-async-functions/)

Although this would be fighting the language...

tgsovlerkhgsel 2021-08-16 12:51:09 +0000 UTC [ - ]

Requiring it for every command by default sucks, but on the other hand, the ability to easily make scripts async is a huge benefit.

I've seen so many cases of processes being synchronous simply because doing it differently would require an unrealistic amount of custom parallelism code.

TeMPOraL 2021-08-16 09:00:12 +0000 UTC [ - ]

What does "DX" stand for in "tons of DX improvements"?

DaGardner 2021-08-16 09:00:49 +0000 UTC [ - ]

Developer Experience I suppose

kleiba 2021-08-16 09:28:06 +0000 UTC [ - ]

Oh man, I'm getting too old for this shit...

marton78 2021-08-16 09:46:07 +0000 UTC [ - ]

It's like UX but for developers...

TeMPOraL 2021-08-16 10:19:09 +0000 UTC [ - ]

Which makes no sense if the developers are the users...

But in the spirit of "there are only two business models - bundling and unbundling", I guess there are only two marketing tricks: use an old term for a new thing, and introduce a new term for an old thing...

zeroxfe 2021-08-16 13:17:21 +0000 UTC [ - ]

Or more charitably, while the UX/DX distinction isn't very meaningful for this project, there are lots of products (e.g., payments) that target both (non-developer) end users and developers. It helps to be able to separate the personas.

TeMPOraL 2021-08-16 13:48:54 +0000 UTC [ - ]

I don't think this holds. As the rule goes, there are only three cardinal numbers: zero, one, many. What are the chances you product has only two meaningful personas - "users" and "developers"?

Take that payment system. People who buy things are obviously users, people who write CMS plugins for that system are obviously developers. But what about, say, analysts studying reports from that system? Accountants making sure the money flows where it should? Sysadmins keeping the backend components running? These are all users too.

Where UX makes sense as a broad concept, giving a separate acronym to one small subset of potential users... doesn't make sense.

zeroxfe 2021-08-16 18:02:46 +0000 UTC [ - ]

It's perfectly reasonable (and quite common) to have acronyms for your major personas, and generic terminology for the tail.

hnlmorg 2021-08-16 09:44:48 +0000 UTC [ - ]

My guess is "deluxe" as used a lot in gaming titles, eg Pokkén Tournament DX

ggambetta 2021-08-16 12:58:11 +0000 UTC [ - ]

I thought this was going to be somehow related to the ZX Spectrum :(

ilaksh 2021-08-16 09:13:09 +0000 UTC [ - ]

I feel like the await keyword everywhere is a bit verbose. One might use something like the gpp preprocessor (hopefully the macros could be defined in a separate file):

        #!/usr/bin/env zx

        #define _ await $
        #define __ await Promise.all

        #define _1 process.argv[1]
        #define _2 process.argv[1]
        #define _3 process.argv[1]

        _`cat package.json | grep name`

        let branch = _`git branch --show-current`
        _`dep deploy --branch=${branch}`

        __([
          $`sleep 1; echo 1`,
          $`sleep 2; echo 2`,
          $`sleep 3; echo 3`,
        ])

        let name = 'foo bar'
        _`mkdir /tmp/${_1}`

2021-08-16 15:54:08 +0000 UTC [ - ]

williamdclt 2021-08-16 09:21:58 +0000 UTC [ - ]

I don't think it is very relevant to critique the Javascript syntax on a post about a specific library

ilaksh 2021-08-16 15:55:13 +0000 UTC [ - ]

I am not talking about JavaScript in general. I have been doing mainly JavaScript programming for the last 8 or 9 years or so (before that other languages like C# and C++ for many years). And I use those keywords all the time.

For this specific use case, they are trying to replace shell scripts. So I thought maybe some people might be willing to consider abbreviations for the async and await keywords for this case.

masklinn 2021-08-16 09:38:55 +0000 UTC [ - ]

This is a node package, so using async/await would have been a specific design decision of the library.

jpxw 2021-08-16 10:56:07 +0000 UTC [ - ]

After reading about various vulnerabilities which are the direct result of backwards JS language features - most recently prototype pollution - I’d be hesitant to use JS for writing scripts.

Maybe I’m just being paranoid.

tgsovlerkhgsel 2021-08-16 12:53:51 +0000 UTC [ - ]

I think a much bigger concern is the ecosystem.

The node ecosystem is built around having third-party dependencies for everything, which makes it impossible to meaningfully vet the code you're running, and once a dependency gets hijacked, all its dependencies are screwed too.

shell0x 2021-08-17 00:41:55 +0000 UTC [ - ]

This looks horrible to me. The mixing of bash commands in Javascript looks absolutely terrible and running node itself for scripting is a total mess(node_modules, versions).

I usually go with bash + set -euxo pipefail and if it becomes too complicated I switch to Python.

GoLang/Rust are the perfect tool when distributing tools as a single binare. Where in the world does JS fit in?

lixtra 2021-08-16 15:24:40 +0000 UTC [ - ]

   await $`dep deploy --branch=${branch}`
   …
   await $`mkdir /tmp/${name}`
Code like this[1] looks prone to shell injection

[1] https://github.com/google/zx

mst 2021-08-16 17:18:59 +0000 UTC [ - ]

That example is immediately followed by two sentences of text, of which the second sentence is:

> The zx package provides useful wrappers around child_process, escapes arguments and gives sensible defaults.

lit-html and at least one SQL generating package I've seen use the template string custom interpolation mechanism to auto-escape things - it's a pretty established pattern at this point in javascript land ... but also, yes, until you learn that, it totally does look prone to injection. I've got in the habit of going and finding the template string interpolation function and double checking, because otherwise I find it hard to convince my brain to believe it isn't prone to injection and it interferes with my skim reading the code ;)

pitaj 2021-08-16 15:38:01 +0000 UTC [ - ]

Template tag functions in JS can intercept the interpolation values passed in. So it's possible they're automatically escaping to prevent shell injection.

They could also be parsing out the first word as the command and not using shell execution at all.

lixtra 2021-08-16 15:50:58 +0000 UTC [ - ]

Indeed, escaping is what they seem to do.

bokchoi 2021-08-16 18:34:13 +0000 UTC [ - ]

If you haven't yet, give babashka a try! It's fun writing little scripts in clojure.

https://github.com/babashka/babashka

kcartlidge 2021-08-16 18:43:45 +0000 UTC [ - ]

> ZX 3.0

I was disappointed this link didn't go to another ZX Spectrum emulator :(

soheil 2021-08-16 15:56:55 +0000 UTC [ - ]

Is this a typo?

  console.log(`Files count: ${count}`)
missing $

ptx 2021-08-16 17:37:06 +0000 UTC [ - ]

No, this is an untagged template literal[1], which just generates a string. The other ones are tagged, which means that the template string and the parameters are (separately) passed to the $ function.

[1] https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...

haolez 2021-08-16 16:19:48 +0000 UTC [ - ]

Is this bundled as a static binary? If yes, what's the binary size?

2021-08-16 13:48:29 +0000 UTC [ - ]

underdeserver 2021-08-16 09:35:14 +0000 UTC [ - ]

Very cool!