rgrau
Usually, those scripts are written by people who didn't learn the "weird tricks", and use global variables (they didn't learn that `local` creates local variables), for example.
In bash, many times the "dumb way" takes 10 times more lines, and it's probably buggier than the "smart tricky way". So, in the end it's your choice what side you pick, and when to stop. Or, use a "real programming language" (I hate when people say this LOL)
After a while, you get a bit of stockholm syndrome, and you're just fine with bash as an orchestration language, and lean into unix principles. I accept its limitations, and I think it keeps me on my toes as it repels bloat.
idk if you were expecting an answer, but bash lives in this liminal space in the tower of languages that is worth a thought.
Some of the examples here are interesting, but they show parameter substitution more than colon itself: https://tldp.org/LDP/abs/html/parameter-substitution.html
In small scopes, I tend to inline the `:?` validation inside the arg of the command. `echo "${1:? first param required}"`
Another usecase is to use colon in the body of a while loop, while doing work in the condition of the loop.
while rlwrap -o -S'>> ' tr a-z A-Z ; do :; done
Gives you the "do X while it succeeds. stop when it returns non-0" semantics.I've also written about this and other bash tricks over the years in https://github.com/kidd/scripting-field-guide/blob/master/bo.... You might like them :)
Using brackets like this is something I never thought of, and it's probably why it's hard for me to process it, but I can see it provides nice annotation capabilities, and it's a more self-contained style.
Thx for sharing!
To take advantage of the "leading space" one, I have this, to mark some commands that I never want to record:
unhist () {
alias $1=" $1"
}
unhist unhist
unhist fzf
unhist rghist #custom command that greps .zhistory,... foo |
bar |
baz
You don't have to use backquotes, AND, it allows you to comment line by line, because there's no backslash messing with the parser.I also use a last `|\ncat` so you can delete any line and you don't have to worry about the last line being a bit different than the rest
I created a list of similar tricks in https://github.com/kidd/scripting-field-guide in case anyone wants to take a look
#!/bin/sh
$*
that's my `~/bin/noglob` file, so when I call a zsh script from bash that uses `noglob`, it doesn't blow up. docker save $image | bzip2 | ssh "$host" 'bunzip2 | docker load' echo "${1:-${env_var:?I need a value for that!}}" &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...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.
The % approach works only on one direction.
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.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
Fixed, thanks!
> 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 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!
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(" | "))[] foo="ls -las"
$foo
"$foo"
for zsh to split words, `setopt SH_SPLIT_WORDS`.I'm trying to maintain a list of radios in .pls/.m3u format [1], so I can choose how I play them (emacs+mplayer).
- Don't like the current song? m-x kill-radio RET
- Want to store the current name of the song? m-x hit RET
Making the interface as painless as possible is part of what makes music for programming more relaxing to me. I find strange there are not more of those kinds of repos around (I haven't found them)
:(){ :|:& };:
Turns into a less mysterious: bomb() {
bomb | bomb &
}
bomb
I started a booklet with some of these tricks and explanations in https://raimonster.com/scripting-field-guide/, in case anyone wants to give feedback (or PRs), it'd be much appreciated.You can try evaluating this in the scratch buffer
(if (member 'nativecomp features)
(message "yay")
(message "nay"))
Or check if a non-interactive function called `native-compile` exists.Or open help for an elisp function (next-line, for example):
c-h f next-line RET
Gives me: next-line is an interactive native compiled Lisp function in ‘simple.el’.
Or, m-x disassemble next-line RETI never liked those "bare minimum templates" that are 100 lines, because usually the scripts I write start being just a couple dozen lines. If they grow, I add things on a need basis, but the ratio of logic/template has to be >0 always.
wrt completions, doing smart completions is hard, and the zsh ones are not very intuitive to me. I try to make my scripts work with "compdef _gnu_generic ". It goes a long way, and it's an incentive to write proper --help