Process all arguments except the first one (in a bash script)
BashShellBash Problem Overview
I have a simple script where the first argument is reserved for the filename, and all other optional arguments should be passed to other parts of the script.
Using Google I found this wiki, but it provided a literal example:
echo "${@: -1}"
I can't get anything else to work, like:
echo "${@:2}"
or
echo "${@:2,1}"
I get "Bad substitution" from the terminal.
What is the problem, and how can I process all but the first argument passed to a bash script?
Bash Solutions
Solution 1 - Bash
Use this:
echo "${@:2}"
The following syntax:
echo "${*:2}"
would work as well, but is not recommended, because as @Gordon already explained, that using *
, it runs all of the arguments together as a single argument with spaces, while @
preserves the breaks between them (even if some of the arguments themselves contain spaces). It doesn't make the difference with echo
, but it matters for many other commands.
Solution 2 - Bash
If you want a solution that also works in /bin/sh
try
first_arg="$1"
shift
echo First argument: "$first_arg"
echo Remaining arguments: "$@"
shift [n]
shifts the positional parameters n times. A shift
sets the value of $1
to the value of $2
, the value of $2
to the value of $3
, and so on, decreasing the value of $#
by one.
Solution 3 - Bash
Working in bash 4 or higher version:
#!/bin/bash
echo "$0"; #"bash"
bash --version; #"GNU bash, version 5.0.3(1)-release (x86_64-pc-linux-gnu)"
In function:
echo $@; #"p1" "p2" "p3" "p4" "p5"
echo ${@: 0}; #"bash" "p1" "p2" "p3" "p4" "p5"
echo ${@: 1}; #"p1" "p2" "p3" "p4" "p5"
echo ${@: 2}; #"p2" "p3" "p4" "p5"
echo ${@: 2:1}; #"p2"
echo ${@: 2:2}; #"p2" "p3"
echo ${@: -2}; #"p4" "p5"
echo ${@: -2:1}; #"p4"
Notice the space between ':' and '-', otherwise it means different:
> ${var:-word} If var is null or unset,
> word is substituted for var. The value of var does not change.
>
> ${var:+word} If var is set,
> word is substituted for var. The value of var does not change.
Which is described in:Unix / Linux - Shell Substitution
Solution 4 - Bash
http://wiki.bash-hackers.org/scripting/posparams
It explains the use of shift
(if you want to discard the first N parameters) and then implementing Mass Usage
Solution 5 - Bash
Came across this looking for something else.
While the post looks fairly old, the easiest solution in bash is illustrated below (at least bash 4) using set -- "${@:#}"
where # is the starting number of the array element we want to preserve forward:
#!/bin/bash
someVar="${1}"
someOtherVar="${2}"
set -- "${@:3}"
input=${@}
[[ "${input[*],,}" == *"someword"* ]] && someNewVar="trigger"
echo -e "${someVar}\n${someOtherVar}\n${someNewVar}\n\n${@}"
Basically, the set -- "${@:3}"
just pops off the first two elements in the array like perl's shift and preserves all remaining elements including the third. I suspect there's a way to pop off the last elements as well.