It seems there's no support yet for Fish shell, zsh, or nushell.
comments
Anybody did any benchmarks? When I switched to oxc in the pipeline at work, I shaved off minutes of the running time. (It was a simple web SPA.) Curious how long it would take for a large collection of scripts.
DRY is from a time where one-letter variables were common.
That's absolutely not the case. Please look into the principle instead of assuming you know what it means.
I think it makes it easier to read, because the other variable assignments are also this way. DRY is from a time where one-letter variables were common.
I'd you're concerned about this, it's up to you to change your bash script style.
Use "set -euo pipefail" and don't use ": =". You can't stop others from doing so though. It's their code, their choice.
I never use ": =" in bash though.
But that has the same effect like DB_HOST="${DB_HOST:-localhost} (use the string if not set), which is more readable.
I disagree that the duplicate reference would be more readable. Instead, the reader needs (if they care about the meaning of the code) to double-check whether the two duplicate names are exactly the same, or whether they are subtly different. At which point the reader needs to wonder why the code isn't written using the form without the repeated name. So, that's not a readability improvement.
Related to that: Code with duplicate references in a single expression or statement leaves open the likelihood that one or more of them will contain a typo or an easily-overlooked difference, leading to bugs. DRY is a good principle to avoid that.
I've seen plenty bugs that were caused by USER_NAME vs USERNAME and similar in 2026. But if thats not a concern and you think the alternatives are clearer... nobody's forcing you.
Ok, from a 90s viewpoint.
The argument for : "${foo:=x}" is usually that you don't have to repeat foo, leading to less opportunity for errors and generally DRY.
Thanks for your hint! After some experimentation and man page reading, this was what I was interested in:
inotifywait --event modify,create ./targetfolder/; echo "new change, that I am interested in, occurred in targetfolder";
I was interested in both file modification and file creation events.
inotifywait /path/to/file
Example:
inotifywait test.file; echo "test.file just changed"
Then in another terminal do something like touch test.file
Bash is everywhere—embedded systems, minimal containers, legacy servers. Zero dependencies, just #!/bin/bash. In constrained environments, you often can't install "proper" languages. It's often the right and only tool for the job.
The article mentions "GNU getopt" but as far as I know GNU doesn't have a getopt utility; the version on most Linux OSes comes from util-linux. (Perhaps the author is confusing it with the C function with the same name.)
Note that other getopt implementations have different features and some are simply broken. For example, BSD getopt doesn't support long options and comes with this known bug:
Arguments containing whitespace or embedded shell metacharacters generally will not survive intact; this looks easy to fix but isn't.
For cross-platform scripts it's probably best to use the getopts shell builtin instead, the downside being it only supports fairly basic (POSIX) syntax even on Bash.
There is also the manual way, I am not saying it's perfect but sometimes it offers better alternative than getopt.
https://gist.github.com/dgoguerra/9206418
I've got one from stackoverflow i tidied up and expanded, that handles long options as well, but you really should learn Python instead. Talking from experience; even with a state machine approach and helpful little functions and debug helpers, juggling so much input is hard in shell.
Well, you're warned now and here it is:
tool_name="tool"
tool_descr="tool does tool things"
printhelp() {
printf '%s\nSyntax: %s [options]...\n%s\n' "$tool_descr" "$tool_name" "$tool_args"
}
bool() { [ -n "$OPTARG" ] && error "--${OPT} accepts no parameters" 7; }
# cli-parser
#--------------------------------------------------------------
tool_args='
-s, --stuff stuff to do
-o, --other other stuff to do
-V, --verbose Tell what i do
-v, --version Print version of this tool and exit
-h, --help This help text
'
while getopts "vVhbs:o:-:" OPT; do
# support long options: https://stackoverflow.com/a/28466267/519360
if [ "$OPT" = "-" ]; then # long option: reformulate OPT and OPTARG
OPT="${OPTARG%%=*}" # extract long option name
OPTARG="${OPTARG#"$OPT"}" # extract long option argument (may be empty)
OPTARG="${OPTARG#=}" # if long option argument, remove assigning `=`
fi
case "$OPT" in
s | stuff ) arg_stuff="$OPTARG"
;; o | other ) arg_other="$OPTARG"
;; V | verbose ) bool; verbose=true
;; v | version ) bool; printversion; exit 0
;; h | help ) printhelp; exit 0
;; ??* ) error "Illegal option --$OPT" 22 # bad long option
;; : ) exit 2 # missing parameter (error reported via getopts)
;; ? ) exit 22 # bad short option (error reported via getopts)
esac
done
[ $OPTIND -eq 1 ] && \
if { [ -e "$1" ] && [ $# -gt 0 ]; } # check for lazy file argument
then lazy_arg="$1"
else printhelp && exit 0
fi
shift $((OPTIND-1)) # remove parsed options and args from $@ list
I still think my favorite shell, NuShell, handles this the best:
def alphabet [
--alpha (-a)
--charlie (-c): string # comments on these lines are parsed and used for automatically generated --help flag
--delta: int
...filenames: string
] { echo \$alpha }"
So much less boilerplate
While I agree with you, I think it's a bit unkind to reply in this way. Sometimes bash is all you have, and it's interesting to learn about tools even if you're unlikely to use them.
If you find yourself needing this, the correct thing to do is to stop writing that shell scripts and switch to a proper language.
The bash man page is full of useful bits like this, but is is densely packed. It's definitely worth reading though.
Perfect, thanks for the explanation. Indeed, I found the same solution via StackOverflow about simultaneously.
You can use the <( ) replacement for this as it runs a command in a subshell and replaces it with the filename of a temporary fifo. So something like:
join <( echo "${var1}" ) <( echo "${var2}" )
Ah that's good to know about zsh.
Sorry regarding the second code block; it does indeed work as intended, and quite elegantly.
The quoting oversight was due to me testing the first one only on zsh, which quotes differently.
The second was tested on Busybox ash and dash against the input in the example. It does assign a number just smaller or equal to threshold because head is overwritten on each iteration until it lands on the last value that was less than or equal to the threshold.
For the first code snippet to run correctly, $list would need to be put in double quotes: echo "$list" | ... , because otherwise echo will conflate the various lines into a single line.
The for loop approach is indeed quite readable. To make it solve the original task (which here means that it should also assign a number just smaller than $threshold to $tail, if $threshold is not itself contained in $list), one will have to do something in the spirit of what @Ephera@lemmy.ml and I describe in these comments.
For the simpler case of threshold match and larger, with the list already ordered, you could use sed:
echo $list | sed -n '/^150$/,$p'
The edge case is tricky because "equal or lower" can't be expressed with regex cleanly, so even an awk solution would look kinda convoluted, so I personally prefer a for loop for readability's sake:
for i in $list; do
if [ "$i" -le "$threshold" ]; then
head="$i"
else
tail="$tail\n$i"
fi
done
printf '%b\n' "$head$tail"