Hacker Newsnew | past | comments | ask | show | jobs | submit | rgrau's commentslogin

I use a variant with ssh and some compression:

    docker save $image | bzip2 | ssh "$host" 'bunzip2 | docker load'


If you are happy with bzip2-level compression, you could also use `ssh -C` to enable automatic gzip compression.


You can also nest those, so this way you can get a value from an argument, or an env var, and if none is set, error.

    echo "${1:-${env_var:?I need a value for that!}}"


Ooh, I didn't know you could nest 'em! ChatGPT never told me that! Now we're getting somewhere! :)

    echo "${1:-${env_var:?I need a value for that!}}"
That is awesome! :)

Like massively concise construct. I don't know what other language can compete:

  console.log(process.argv[2] || process.env.VAR || console.error("I need a value for that"));
I personally prefer the bash v


It blows my mind how big a deal argument parsing is in legacy scripting languages (including python).

That snippet is concise, but relies on the user supplying arguments in the order you demand. AFAICS, non-trivial scripts require you to loop over arguments, testing against long and short forms of parameters, and shifting if the parameter expects an argument.

In Powershell, you define your parameter and apply constraints. Voila:

    [Parameter(Mandatory)]
    [ValidateRange(1, 20)]
    [int]$foo
That's it, the entire thing, done.


Thanks for that. I'm currently migrating a set of bash scripts to PS1 for win compatibility. This is gonna help me! Undeniably a good feature. Sure there's the case / getopts idiom for parsing args in bash as you say, but I'd say this is a place PS excels them in. I totally agree that arg parsing should be standardized and simple like this. A nice CLI is just such a joy to use. Ideally something that includes usage info and (like the PS example seemingly) optionality.

Syntactically I'd even prefer a single line, like

  [Pram(musthave):In(1, 20)/"Foos excessive or inadequate":int/$foo:"Foo count"/"Please supply how many foos you want."]


If you call python a legacy scripting language, i'll call Windows (where powershell runs on) a legacy operating system.


Sure, Windows doesn't have "legacy" like VMS or Unix etc, but it's been in use by every day people longer than any other current OS except for MacOS, which really isn't the same OS it launched as, whereas Windows has maintained backwards compatibility (for better for for worse) for decades. So.. Legacy? Why not.


This is the most civilized flame war I have ever seen. :)


I didn't mean to describe python as "legacy"; it is a great choice for scripting in the year 2023. It's second only to pwsh for that.

I use pwsh on Linux every day.

Anything that isn't a lisp machine is a legacy OS ;-)

I realise I've given offense, for which I'm sorry, but I'm driven not so much to denigrate bash as to advocate for a world where shells are semantic.


Here's a solution in k, that uses a similar array oriented approach:

    &2=+/~x!/:\:x:!100
I wrote a little explanation of it, in case anyone is curious about how it works: https://github.com/kidd/arraylangs-index/blob/master/noteboo...


I couldn't find a way to have more than one callback per signal, and created a system to have an array of callbacks:

https://github.com/kidd/scripting-field-guide/blob/master/bo...

A nice bonus is that it also keeps the return value of the last non-callback function, so your script behaves better when called from other scripts.


I have 2 use cases for cf), but I don't use it a lot in the end:

One is when inside a parenthesis, and wanting to really delete till the closing parenthesis. But that would leave an unbalanced open paren. So in this case, I use ct) most of the times.

The other is when the cursor is before the opening parenthesis, and I want to delete the whole block. In that case, I found c% to be easier to me. The advantage being that it works with other delimiters ({[]}) handles nesting better, and it's multiline friendly.

If instead of c%, we speak about d%, another plus is that dot (.) will repeat the generic command, so

    if (is_foo()) {

      return 1;
    }
can be cleared with `d%.` from the beginning of the first line.


ca( and ci( might be what you’re looking for.


Yep, good point. They are useful when you want to change the whole text inside the delimiters (and IME, it's most of the times), but they do different things than cf( because they also change/delete text behind the cursor.

The % approach works only on one direction.


`c])` is also pretty handy when you're within a bunch of parentheses. For instance,

    if funca(funcb(red, green), funcc(blue, yellow)) {
                                ^
If you are where the arrow is, `c])` will change the second argument. If you were on the comma before it, `d])` will remove all but the first argument.


Another advantage of pipes at the end is that you can comment lines and the full pipeline still works.

Some time ago I wrote a bunch of tips to make more ergonomic bash scripts: https://raimonster.com/scripting-field-guide/index.html

Also, Perl's diamond operator does the DWIM thing with files/stdin, and it's used directly as a line iterator. It handles multiple files (or none) in a row, which is a nice plus :) https://perlmaven.com/the-diamond-operator


Here's where he explains how he did it: https://www.youtube.com/watch?v=ORjyXcLDd9M


> If appropriate, change to the script’s directory close to the start of the script.

> And it’s usually always appropriate.

I wouldn't think so. You don't know where your script will be called from, and many times the parameters to the script are file paths, which are relative to the caller's path. So you usually don't want to do it.

I collected many tips&tricks from my experience with shell scripts that you may also find useful: https://raimonster.com/scripting-field-guide/


I agree. I make an effort to not change directory wherever possible and if a change is needed, do it in a subshell and just for the command that needs it (hardly any commands actually need it, anyway).

Edit: just had a quick look at your recommended link and spotted a "mistake" in 4.7 - using "read" without "-r" would get caught out by shellcheck.


Fixed, thanks!


In e.g. "Read the great Oil Shell blogpost." it's not clear there's a link there: the "blogpost" is a link but you only see that if you hover your mouse.


Oh, I hadn't noticed that links are not highlighted as such (unless already visited).

Fixed, thanks!


A very useful function in jq is "join", which I use a lot to cook the final shape of the data (many times used with fzf/dmenu)

Here's a simple way to list and browse github issues of a given user/repo:

    #!/usr/bin/env sh

    browse_url() {
      firefox http://github.com/$1/issues/$2
    }

    issue=$(curl https://api.github.com/repos/$1/issues |
          jq -r 'map([(.number|tostring), .title] | join(" | ")) | join("\n")' |
          dmenu -i -l 10 |
          awk "{print \$1}")

    browse_url $1 $issue

Although the `| join("\n")` part could be done in a more idomatic way with just `[]`, sometimes the manual way are still clearer to me:

    map([(.number|tostring), .title] | join(" | "))[]


Personally I find it clearer in many cases to use a format string instead. ie. instead of writing:

    [(.number|tostring), .title] | join(" | ")
I would write:

    "\(.number) | \(.title)"
which IMO is more readable in cases where you have specific values you want to put in specific places, as opposed to a list of unknown length which you want joined (eg. I would still use join("\n") in your example).


Oh!

I didn't know that one could build an arbitrary string like that inside a map.

Thanks a lot for that, I agree it looks better!


Even funnier when you realize bash and zsh do different things (by default) there.

   foo="ls -las"
   $foo
   "$foo"
for zsh to split words, `setopt SH_SPLIT_WORDS`.


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

Search: