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}";
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.
– Rockallite
Feb 09 '17 at 01: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?
– terdon
Feb 09 '17 at 09:13
argv=("$@")
, there are only command line arguments, no script name. So "${argv[@]:1:2}
will be the actual 2nd and 3rd command line arguments, while ${@:1:2}
is the 1st and 2nd command line arguments.
– Rockallite
Feb 09 '17 at 09:49
"${@:1:2}"
for *2nd and 3rd elements from $@
*. Nothing wrong. Just a bit confusing for me. And I want to clarify it.
– Rockallite
Feb 09 '17 at 09:51
0
and not at 1
. So the element at index 1
is actually the second and not the first. Now, when you print "$@"
, you are printing a string, not an array, and apparently bash will remove the script name automatically. Basically, $@
is special and doesn't behave like other arrays. This probably merits its own question.
– terdon
Feb 09 '17 at 10:50
echo "${A[@]:1:2}"
to get two elements starting at position 1 in array A. As noted above, echo "${A:1:2}"
will give two characters from the first element, starting with the character at position 1. The quotes are required if the elements of A contain spaces, if you want to preserve element structure.
– Stuart R. Jefferys
Nov 13 '17 at 18:33
echo "${@:2}"
gives the 2nd command-line argument, and onwards, to the very end. Can you add this as an example, and an explanation of it, to your answer too?
– Gabriel Staples
Aug 16 '21 at 19:23
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. – jordanm Jul 07 '13 at 03:05