The thing you tried:
first_arg=$1
shift
# ...later...
else
node default.js "$first_arg" "$@"
fi
This would have been identical to your first variant provided that there are at least one command line argument.
With no command line arguments "$first_arg"
would still be an empty string, and therefore an argument, whereas "$@"
would not generate even an empty string.
If your Node application accepts an empty argument on the command line, then this may make the application's behave different in your two code variants.
If calling your script with no command line arguments is a valid thing to do, you could do
node default.js ${first_arg:+"$first_arg"} "$@"
where ${first_arg:+"$first_arg"}
would expand to nothing if first_arg
is empty or unset, but to "$first_arg"
if first_arg
was set to a non-empty string. Or, if you want to cause an explicit failure for an unset or empty variable:
node default.js "${first_arg:?Error, no command line arguments}" "$@"
Alternatives includes making a copy of $@
as a bash
array as Jesse_b shows in his answer.
Putting $first_arg
back into $@
with
set -- "$first_arg" "$@"`
would not work as this would include an empty argument as $1
in $@
if the command line argument was missing.
With
set -- ${first_arg:+"$first_arg"} "$@"`
you would "unshift" nothing if $first_arg
was empty or if the variable did not exist.
Note that shift is the same as shift 1 and that single statements don't need to be terminated by ; unless followed by another statement on the same line (newline is a command terminator, just like ;).
"$@"
is better than"$1" "${@:2}"
, which will create an extra argument if$@
is empty. – Dennis Jul 14 '18 at 04:41"$@"
and"${@}"
in a special way, allowing it correctly pass through quoted args (likearg1 "arg two" arg3
), see: https://stackoverflow.com/a/53214779/274503 – Yarek T May 25 '23 at 16:08