I have a script that takes parameters and I want to remove given named parameters
e.g. script.sh a b c and I want to remove 'b' so that
$1 = a
$2 = c
This also must work for any given set of args such that e.g.
script.sh "a 1" b "c 2"
$1 = "a 1"
$2 = "c 2"
A previous answer said
for var in "$@"; do
case $var in
"a") echo -n $var ;;
"b") ;;
esac
done
The generic version of the previous answer should have been (in order to remove b)
for var in "$@"; do
case $var in
"b") ;;
*) echo -n $var ;;
esac
done
But this fails for multiple parameters e.g.
script.sh a b c
Output: ac
We wanted a b and we wanted them in positional parameter $1=a and $2=b
So a better answer is needed.
In the special case (commonly occurring) that you want to remove some initial positional parameters, you use shift. By default that deletes $1; with a numeric argument, it will delete n parameters.
Now, in your specific case, we can use a combination of shift and set --.
local a=$1
shift 2 # delete $1 and $2
set -- "$a" "$@" # insert $1 before original $3 ... $n
Using Bash arrays is another possibility. If we translate the "$@" arguments into a bash array.
local args=("$@") # convert $1 $2 ... into ${args[0]} ${args[1]} ...
unset args[1] # delete args[1]; note: elements DO NOT SHIFT DOWN!
set -- "${args[@]}" # convert array back to positional params
When we convert the array back to positional params with the "${args[@]}" expansion syntax, the unset args[1] element is absent, and so the original $2 disappears.
Of course, if we need those arguments in order to pass them to a function or script, we don't have to convert the array back to positional parameters. Just:
local args=("$@") # convert $1 $2 ... into ${args[0]} ${args[1]}
unset args[1] # delete second arg
script "${args[@]}" # call script with second argument deleted
Likewise, in my very first example, we could just call whatever we need to call rather than using set to further edit the positionals:
local a=$1 # preserve $1 in temporary variable
shift 2 # delete $1 and $2
script "$a" "$@" # call target script with original $1 $3 $4 ...
Try this Shellcheck-clean Bash code:
#! /bin/bash -p
args=()
for a in "$@"; do
[[ $a == b ]] || args+=( "$a" )
done
set -- "${args[@]}"
(( $# > 0 )) && printf '%s\n' "$@"
When run with arguments 'a 1' b 'c 2' it produces output
a 1
c 2
When run with arguments -x "a'1" b 'c 2' "'\$(echo REBOOTING >&2)'" it produces output
-x
a'1
c 2
'$(echo REBOOTING >&2)'
The -- argument to set prevents subsequent arguments (e.g. -x) being treated as options.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With