Get the index of a value in a Bash array

后端 未结 15 625
说谎
说谎 2021-01-30 03:41

I have something in bash like

myArray=(\'red\' \'orange\' \'green\')

And I would like to do something like

echo ${         


        
15条回答
  •  情深已故
    2021-01-30 04:36

    Another tricky one-liner:

    index=$((-1 + 10#0$(IFS=$'\n' echo "${my_array[*]}" | grep --line-number --fixed-strings -- "$value" | cut -f1 -d:)))
    

    features:

    • supports elements with spaces
    • returns -1 when not found

    caveats:

    • requires value to be non-empty
    • difficult to read

    Explanations by breaking it down in execution order:

    IFS=$'\n' echo "${my_array[*]}"
    

    set array expansion separator (IFS) to a new line char & expand the array

    grep --line-number --fixed-strings -- "$value"
    

    grep for a match:

    • show line numbers (--line-number or -n)
    • use a fixed string (--fixed-strings or -F; disables regex)
    • allow for elements starting with a - (--)

      cut -f1 -d:

    extract only the line number (format is :)

    $((-1 + 10#0$(...)))
    

    subtract 1 since line numbers are 1-indexed and arrays are 0-indexed

    • if $(...) does not match:

      • nothing is returned & the default of 0 is used (10#0)
    • if $(...) matches:
      • a line number exists & is prefixed with 10#0; i.e. 10#02, 10#09, 10#014, etc
      • the 10# prefix forces base-10/decimal numbers instead of octal


    Using awk instead of grep, cut & bash arithmetic:

    IFS=$'\n'; awk "\$0 == \"${value//\"/\\\"}\" {print NR-1}" <<< "${my_array[*]}"
    

    features:

    • supports elements with spaces
    • supports empty elements
    • less commands opened in a subshell

    caveats:

    • returns when not found

    Explanations by breaking it down in execution order:

    IFS=$'\n' [...] <<< "${my_array[*]}"
    

    set array expansion separator (IFS) to a new line char & expand the array

    awk "\$0 == \"${value//\"/\\\"}\" {print NR-1}"
    

    match the entire line & print the 0-indexed line number

    • ${value//\"/\\\"} replaces double quotes in $value with escaped versions
    • since we need variable substitution, this segment has more escaping than wanted

提交回复
热议问题