Hot answers tagged

135

You can access the array indices using ${!array[@]} and the length of the array using ${#array[@]}, e.g. : #!/bin/bash array=( item1 item2 item3 ) for index in ${!array[@]}; do echo $index/${#array[@]} done Note that since bash arrays are zero indexed, you will actually get : 0/3 1/3 2/3 If you want the count to run from 1 you can replace $index by $...


116

As of bash 4.2, you can just use a negative index ${myarray[-1]} to get the last element. You can do the same thing for the second-last, and so on; in Bash: If the subscript used to reference an element of an indexed array evaluates to a number less than zero, it is interpreted as relative to one greater than the maximum index of the array, so negative ...


112

To add an element to the beginning of an array use. arr=("new_element" "${arr[@]}") Generally, you would do. arr=("new_element1" "new_element2" "..." "new_elementN" "${arr[@]}") To add an element to the end of an array use. arr=( "${arr[@]}" "new_element" ) Or instead arr+=( "new_element" ) Generally, you would do. arr=( "${arr[@]}" "new_element1"...


83

Just use array syntax on the assignment and quote your variable: array=("${array[@]:1}") #removed the 1st element Edit according to question in comment. For $@ you can use it like this: set -- "${@:2}" #removed the 1st parameter


73

When you use ./scriptname.sh it executes with /bin/bash as in the first line with #!. But when you use sh scriptname.sh it executes sh, not bash. The sh shell has no syntax to create arrays, but Bash has the syntax you used.


60

/bin/sh is hardly ever a Bourne shell on any systems nowadays (even Solaris which was one of the last major system to include it has now switched to a POSIX sh for its /bin/sh in Solaris 11). /bin/sh was the Thompson shell in the early 70s. The Bourne shell replaced it in Unix V7 in 1979. /bin/sh has been the Bourne shell for many years thereafter (or the ...


54

Just use: mkdir -p -- "${array1[@]}" That will also create intermediary directory components if need be so your array can also be shortened to only include the leaf directories: array1=( /apache/bin /apache/conf /apache/lib /www/html /www/cgi-bin /www/ftp ) Which you could also write: array1=( /apache/{bin,conf,lib} /www/{html,cgi-bin,...


53

Modern bash (v4.1 or better) You can read the last element at index -1: $ a=(a b c d e f) $ echo ${a[-1]} f Support for accessing numerically-indexed arrays from the end using negative indexes started with bash version 4.1-alpha. Older bash (v4.0 or earlier) You must get the array length from ${#a[@]} and then subtract one to get the last element: $ ...


41

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


40

You can get the list of "keys" for the associative array like so: $ echo "${!astr[@]}" elemB elemA You can iterate over the "keys" like so: for i in "${!astr[@]}" do echo "key : $i" echo "value: ${astr[$i]}" done Example $ for i in "${!astr[@]}"; do echo "key : $i"; echo "value: ${astr[$i]}"; done key : elemB value: 199 key : elemA value: 123 ...


39

Virtually all shell arrays (Bourne, csh, tcsh, fish, rc, es, yash) start at 1. ksh is the only exception that I know (bash just copied ksh). Most interpreted languages at the time (early 90s): awk, tcl at least, and tools typically used from the shell (cut -f1-3, head -n 3, sort -k1,3, cal 1 2015, comm -1) start at 1. sed, ed, vi number their lines from 1... ...


32

The syntax delete array is not in current versions in POSIX, but it is supported by virtually all existing implementations (including the original awk, GNU, mawk, and BusyBox). It will be added in a future version of POSIX (see defect 0000544). An alternate way to clear all array elements, which is both portable and standard-compliant, and which is an ...


27

Using jq : $ cat json [ { "item1": "value1", "item2": "value2", "sub items": [ { "subitem": "subvalue" } ] }, { "item1": "value1_2", "item2": "value2_2", "sub items_2": [ { "subitem_2": "subvalue_2" } ] } ] CODE: arr=( $(jq -r '.[].item2' json) ) printf '%s\n' "${arr[@]}" ...


25

Little late, but I don't see the ideal sh answer here so I'll chime in. If you don't need subscripting, then sh effectively does support arrays. It just supports them as space separated strings. You can print the entire contents of them, "push" to them, or iterate through them just fine. Here's a bit of sample code: NAMES="" NAMES="${NAMES} MYNAME" NAMES="$...


25

This is an instance of pattern replacement in shell parameter expansion: ${parameter/pattern/replacement} expands ${parameter}, replacing the first instance of pattern with replacement. In the context of a pattern of this kind, # is special: it anchors the pattern to the start of the parameter. The end result of all this is to expand all the values in the ...


22

The difference is subtle; "$*" creates one argument, while "$@" will expand into separate arguments, so: LIST=(1 2 3) for i in "${LIST[@]}"; do echo "example.$i" done will deal with the list (print it) as multiple variables but LIST=(1 2 3) for i in "${LIST[*]}"; do echo "example.$i" done will ...


22

I think you're asking two different things there. Is there a way to make bash print this info without the loop? Yes, but they are not as good as just using the loop. Is there a cleaner way to get/print only the key=value portion of the output? Yes, the for loop. It has the advantages that it doesn't require external programs, is straightforward, and ...


21

You cannot pass two arguments with single option using getopts. I recommend the following alternatives: Put quotes around multiple arguments In this case getopts will treat them as one argument, but you will be able to split it later on. You can even put all arguments in the array at once: #!/bin/bash while getopts ":hr:l:" opt; do case $opt in ...


21

unset removes an element. It doesn't renumber the remaining elements. We can use declare -p to see exactly what happens to numbers: $ unset "numbers[i]" $ declare -p numbers declare -a numbers=([0]="53" [1]="8" [2]="12" [3]="9" [5]="69" [6]="8" [7]="7" [8]="1") Observe the numbers no longer has an element 4. Another example Observe: $ a=() $ a[1]="...


20

Unconventional approach (all not pure bash): if all elements in an array are just one characters (like in the question) you can use rev: echo "${array[@]}" | rev otherwise: printf '%s\n' "${array[@]}" | tac | tr '\n' ' '; echo and if you can use zsh: echo ${(Oa)array}


20

Another unconventional approach: #!/bin/bash array=(1 2 3 4 5 6 7) f() { array=("${BASH_ARGV[@]}"); } shopt -s extdebug f "${array[@]}" shopt -u extdebug echo "${array[@]}" Output: 7 6 5 4 3 2 1 If extdebug is enabled, array BASH_ARGV contains in a function all positional parameters in reverse order.


20

To answer the question in the title, you can "shift" an array with the substring/subarray notation. (shift itself works with just the positional parameters.) $ a=(a b c d e) $ a=("${a[@]:1}") $ echo "${a[@]}" b c d e Similarly, to 'pop' the last item off the array: a=("${a[@]:0:${#a[@]} - 1}" ) or unset "a[${#a[@]}-1]" So if you wanted to, you could do ...


20

That's a feature of zsh inherited from csh/tcsh. The $path array variable is tied to the $PATH scalar (string) variable. Any modification on one is reflected in the other. In zsh (contrary to (t)csh), you can tie other variables beside $PATH with typeset -T. It's conventional, but not mandatory, to use an uppercase name for the colon-separated scalar and ...


19

Use a different kind of array: rather than an integer-indexed array, use an associative array, so the key (index) is what you will be checking for. bash-4.0 or later is required for this. declare -A array1=( [prova1]=1 [prova2]=1 [slack64]=1 ) a=slack64 [[ -n "${array1[$a]}" ]] && printf '%s is in array\n' "$a" In the above we don't really ...


19

bash array assignment, reference, unsetting with negative index were only added in bash 4.3. With older version of bash, you can use expression in index array[${#array[@]-1}] Another way, also work with older version of bash (bash 3.0 or better): $ a=([a] [b] [c] [d] [e]) $ printf %s\\n "${a[@]:(-1)}" [e] or: $ printf %s\\n "${a[@]: -1}" [e] Using ...


19

Generally calling: var=value cmd where cmd is a function is not portable. With bash, that only works for scalar variables (and with x=(...) parsed as an array but assigned as a scalar) and there are a number of issues with scoping if you do that, with ksh93 and yash, it works but the variable definition remains afterwards. With mksh, you get a syntax ...


19

I have answered the question as written, and this code reverses the array. (Printing the elements in reverse order without reversing the array is just a for loop counting down from the last element to zero.) This is a standard "swap first and last" algorithm. array=(1 2 3 4 5 6 7) min=0 max=$(( ${#array[@]} -1 )) while [[ min -lt max ]] do # Swap ...


18

All examples presented below work for general case where there's an arbitrary number of words on the line. The essential idea is the same everywhere - we have to read the file line by line and print the words in reverse. AWK facilitates this the best because it already has all the necessary tools for text processing done programmatically, and is most ...


17

comm(1) is a tool that compares two lists and can give you the intersection or difference between two lists. The lists need to be sorted, but that's easy to achieve. To get your arrays into a sorted list suitable for comm: $ printf '%s\n' "${A[@]}" | LC_ALL=C sort That will turn array A into a sorted list. Do the same for B. To use comm to return the ...


16

In your case parenthesis () are used as array definition, for example a=(one two three) # array definition 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 If you put single variable in ...


Only top voted, non community-wiki answers of a minimum length are eligible