Как извлечь конкретный элемент из массива в BASH?

Вот как я создаю массив bash:

while read line
do
   myarr[$index]=$line
   index=$(($index+1))
done < lines.txt

Файл "lines.txt" состоит из следующих строк

hello big world!
how are you
where am I

После создания ${myarr[@]} я могу легко получить доступ к каждому элементу (строке) в этом массиве, выдав

echo ${myarr[2]}

Но что, если я хочу извлечь только world!? Можно ли извлечь world! из 0 элемента myarr? Самое главное, можно ли извлечь последнее слово из элемента myarr?

Я знаю, что в python вы можете сделать myarr[0][3], и это будет делать трюк, как насчет bash?

Ответ 1

Это один из многих способов

set ${myarr[2]}
echo $3

Ответ 2

Вы можете извлекать слова из строки (это элементы массива), используя модификаторы в расширении переменной: # (удалить префикс), ## (удалить префикс, жадный), % (удалить суффикс ) и %% (удалить суффикс, жадный).

$ myarr=('hello big world!' 'how are you' 'where am I')
$ echo "${myarr[0]}"      # Entire first element of the array
hello big world!
$ echo "${myarr[0]##* }"  # To get the last word, remove prefix through the last space
world!
$ echo "${myarr[0]%% *}"  # To get the first word, remove suffix starting with the first space
hello
$ tmp="${myarr[0]#* }"    # The second word is harder; first remove through the first space...
$ echo "${tmp%% *}"       # ...then get the first word of what remains
big
$ tmp="${myarr[0]#* * }"  # The third word (which might not be the last)? remove through the second space...
$ echo "${tmp%% *}"       # ...then the first word again
world!

Как вы можете видеть, вы можете получить здесь довольно причудливое представление, но в какой-то момент предложение @chepner превратить его в массив становится намного проще. Кроме того, формулы, которые я предлагаю для извлечения второго и т.д., Немного хрупки: если вы используете мою формулу для извлечения третьего слова строки, которая имеет только два слова, первая обрезка будет терпеть неудачу, и она завершит печать первое (!) слово вместо пробела. Кроме того, если у вас есть два пробела подряд, это будет рассматривать его как слово с нулевой длиной с пространством на каждой его стороне...

Кстати, при построении массива я считаю, что чище использовать +=(newelement), а не отслеживать индекс массива явно:

myarr=()
while read line, do
    myarr+=("$line")
done < lines.txt

Ответ 3

Аналогичен ответу Стивен-Пенни, но без перезаписи позиционных параметров оболочки/функции.

a=(${myarr[2]})
echo ${a[3]}

Ответ 4

распечатать определенный элемент из массива, используя индекс:

echo ${my_array[2]}

чтобы распечатать все элементы из массива, который вы делаете:

for i in "${my_array[@]}"
do
    echo $i
done