How can I get a slice of $@
in Bash without first having to copy all positional parameters to another array like this?
argv=( "$@" )
echo "${argv[@]:2}";
You can use the same format as for any other array. To extract the 2nd and 3rd elements from $@
, you would do:
echo "${@:1:2}"
- -
| |----> slice length
|------> slice starting index
"${@:1:2}"
actually gives me the 1st and 2nd command line arguments. Meanwhile, "${@:1}"
gives me the full command line arguments, and "${@:0}"
gives me the script name followed by full command line arguments.
Commented
Feb 9, 2017 at 1:56
$@
array are the 1st and 2nd arguments. "${@:1}"
will print the entire array starting with the 2nd element (the 1st argument) and ${@:0}
the entire array starting from the 1st element which is the name of the script. What were you expecting?
In place of using some_array_variable
in your code (argv
in your case), simply use @
in that variable name's place. The symbol @
represents the input argument array, and you can treat it exactly like you'd treat any other array. The confusion is simply that we are accustomed to seeing it almost always paired with the $
character like this: $@
, and so we don't realize that the @
character is the array itself, and can be used alone as an array variable as well.
So, here are some examples:
Slice from the input argument array, @
, which is normally seen and accessed simply as $@
:
# 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
The following are general array reminders to myself that may benefit others landing on this page too.
# store a slice from an array into a new array
new_array=("${@:4}")
# print the entire array
echo "new_array = ${new_array[@]}"
Here is a runnable example of generic array slicing and array element access in bash, inspired by this source:
(Use @
as the input argument array if desired, instead of a
below, according to your use case)
a=(one two three four five six) # define a new array, `a`, with 6 elements
echo "$a" # print first element of array a
echo "${a}" # print first element of array a
echo "${a[0]}" # print first element of array a
echo "${a[1]}" # print *second* element of array a
echo "${#a[@]}" # print number of elements in array a
echo "${a[@]:1:3}" # print 2nd through 4th elements; ie: the 3 elements
# starting at index 1, inclusive, so: indices 1, 2, and 3
# (output: `two three four`)
echo "${a[@]:1}" # print 2nd element onward
Copy and paste all code chunks above into a file called array_slicing_demo.sh
, and mark it executable with chmod +x array_slicing_demo.sh
so that you can run it. Or, just download my demo array_slicing_demo.sh file from my eRCaGuy_hello_world repo here.
Then, run it like this:
./array_slicing_demo.sh a b c d e f g h i j k
...and you will see the following output:
b c d e f b c d e f g h i j k new_array = d e f g h i j k one one one two 6 two three four two three four five six
Keywords: array access in bash; bash array indexing; access elments in arrays in bash; bash array slicing; print arrays in bash; print array elements in bash
I usually do this:
somefunc() {
local message="$1"
shift
echo "message = $message"
echo "other = $@"
}
somefunc first second third goforth
which will print:
message = first
other = second third goforth
You can expand on the concept by shift
ing after second, third, etc. argument
For function parameters, the answer with echo "${@:1:2}"
didn't work for me at all. Also, I wanted the slice-off the first element, since it was a different parameter. What did work was:
function foo(){ #takes single param + array of params
local param1="$1". #first param
local -a tmp=( "${@}" ) #copy all params
local -a rem_params=( "${tmp[@]:1}") #slice off first:Works!
# local -a rem_params=( "${@[@]:1}" ) #DID NOT WORK, ERROR
# local -a rem_params=( "{@:1}" ) #DID NOT SLICE
echo "${rem_params[@]}"
}
Maybe I'll write to test to see how this works with positional arguments for at the script-level, but no time right now.
"$@"
. Youargv
assignment would break if any args contained spaces.