Is there a way to change the command line arguments in a Bash script? For example, a Bash script is invoked like this:
./foo arg1 arg2 Is there a way to change the value of arg1 within the script? Something like:
$1="chintz" You have to reset all arguments. To change, e.g., argument $3:
set -- "${@:1:2}" "new_arg3" "${@:4}" Basically you set all arguments to their current values, except for the one(s) that you want to change. set -- is also specified by POSIX 7.
The "${@:1:2}" notation is expanded to the two (hence the 2 in the notation) positional arguments, starting from offset 1 (i.e. $1). It is a shorthand for "$1" "$2" in this case, but it is much more useful when you want to replace, e.g., "${17}".
Optimising for legibility and maintainability, you may be better off assigning $1 and $2 to more meaningful variables (I don't know, input_filename = $1 and output_filename = $2 or something) and then overwriting one of those variables (input_filename = 'chintz'), leaving the input to the script unchanged, in case it is needed elsewhere.
I found the answer by thkala very helpful, so I have used the idea and expanded on it slightly to enable me to add defaults for any argument which has not been defined. For example:
# Set defaults for the passed arguments (if any) if not defined. # arg1=${1:-"default-for-arg-1"} arg2=${2:-"default-for-arg-2"} set -- "${arg1}" "${arg2}" unset arg1 arg2 $1, $2, etc. in Bash using set --As an addition to the main answer on Ask Ubuntu by @Radu Rădeanu here, and to the main answer by @thkala on Stack Overflow here, I'd like to add a really simple example to set multiple arguments at once like this:
# Set arguments `$1`, `$2`, and `$3` to the strings "one", "two", and "three", # respectively set -- "one" "two" "three" echo "$1 $2 $3" Output:
one two three If you have additional arguments after the arguments you want to change, you can keep them by slicing them onto the end, like this:
# Change just arguments $1, $2, and $3, while keeping arguments $4 and beyond # unchanged set -- "one" "two" "three" "${@:4}" I explain the "${@:4}" slicing syntax in my answer here: Unix & Linux: Bash: slice of positional parameters. See that answer for much more detail on bash array slicing. Here is a small snippet from it:
# Array slicing basic format 1: grab a certain length starting at a certain # index echo "${@:2:5}" # │ │ # │ └────> slice length # └──────> slice starting index # Array slicing basic format 2: grab all remaining array elements starting at a # certain index through to the end echo "${@:2}" # │ # │ # └──────> slice starting index
So, in the main answer by @thkala, which contains this:
# keep arguments $1 and $2 as-is, change argument $3, and keep arguments $4 and # beyond as-is set -- "${@:1:2}" "new_arg3" "${@:4}" ...the explanation is that "${@:1:2}" grabs the first 2 arguments, "new_arg3" inserts that as a new argument 3, and "${@:4}" grabs all arguments from 4 to the end, thereby changing only argument 3 and keeping all other arguments as they were.
For help on the set built-in bash command, see help set or look online here: https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#The-Set-Builtin
help set shows the following for the -- argument:
-- Assign any remaining arguments to the positional parameters. If there are no remaining arguments, the positional parameters are unset.
defaultarg is often helpful, but it does not change the arg.Test MyClassTest.testMethod failed, but to run just that test, I need to pass-Dtest=MyClassTest#testMethod. (Note period vs hash). So I'd like to change any-Dtest=argument, and still be able to runmvn "$@"to get proper quoting of the other arguments. This lets me copy/paste the output directly, rather than having to edit the middle of the string