Now I use this bash command:
$ yarn b types && yarn w types && yarn g types && yarn s types
Is it possible to generate command like this in bash? (pseudo code):
$ exec ['b', 'w', 'g', 's'].map(input => `yarn ${input} types`).join(" && ")
If it is possible, which syntax will be here?
I am going to use this script in my package.json file (node). yarn workspaces foreach not suitable here, because of its poor output
Code generation has serious security implications and is generally only for experts. Moreover, in present circumstances, you don't need it: a loop will suffice.
buildAll() {
for input; do
yarn "$input" type || return
done
}
buildAll b w g s
...has identical behavior, exiting early with a nonzero status if any of yarn b type
, yarn w type
, yarn g type
or yarn s type
fails, and exiting with a successful/zero status if all four succeed.
As a one-liner, this would be:
buildAll() { for i; do yarn "$i" type || return; done; }; buildAll b w g s
This doesn't change in any substantial way if your items are in an array; if you have:
types=( b w g s )
...then, just replace buildAll b w g s
with buildAll "${types[@]}"
Before doing anything you saw here in your own code, review BashFAQ #48 regarding the security issues associated with eval
.
The ${var@Q}
expansion requires bash 5.0 or newer; for older versions of bash, printf %q
is the alternate way to escape variables' contents to be safe to parse as code. Note that this isn't any shorter or more readable than the alternatives above, and still involves a loop!
:
is used as a synonym to true
; it lets us make all iterations of our loop identical, unconditionally prepending a &&
.
types=( b w g s )
statement=':'
for type in "${types[@]}"; do
statement+=" && yarn ${type@Q} types"
done
eval "$statement"
The version with support for older versions of bash is:
types=( b w g s )
statement=':'
for type in "${types[@]}"; do
printf -v type_q '%q' "$type"
statement+=" && yarn $type_q types"
done
eval "$statement"