Как разделить строку по разделителю, что приведет к неизвестному количеству частей, и как собрать результаты в массив?

Вы можете использовать awkдля захвата ipи countryи сохранения в массив:

IFS=$'\n'
IP_country=( $(awk -F'[:"]' '/ip/ || /country/{ print $5}' <<<"$( wget... )") )

Тогда первый элемент — ip, а следующий —country:

printf '%s\n' "${IP_country[0]}"
1.2.3.4
printf '%s\n' "${IP_country[1]}"
IR

Или распечатать все элементы:

printf '%s\n' "${IP_country[@]}"
1.2.3.4
IR

Будущее чтение:

2
12.06.2021, 12:53
2 ответа

В Bash вы можете использовать read -aи здесь строку -, чтобы разбить строку на массив:

path=/foo/bar/doo
IFS=/ read -r -a parts <<< "$path"

Это дало бы массив с четырьмя элементами (пустыми ), foo, barи doo.

Это не работает с путями, содержащими новые строки, так как readпо умолчанию интерпретирует новую строку как разделитель. Чтобы предотвратить это, вам нужно добавить -d '', но тогда есть проблема, что здесь строка -добавляет новую строку, которую затем нужно удалить из последнего элемента:

path=$'/path/with/new\nlines'
IFS=/ read -d '' -r -a parts <<< "$path"
parts[-1]=${parts[-1]%$'\n'}

(parts[-1]относится к последнему элементу массива, а ${var%text}расширяется до значения varс удалением завершающей части, соответствующей text.)

Также обратите внимание, что если путь может содержать повторяющиеся косые черты, например. foo//bar, вы получите пустые элементы массива посередине. Точно так же, если путь заканчивается косой чертой, в конце вы получите пустой элемент.

Вы можете либо игнорировать их, либо предварительно обработать путь, чтобы удалить их, с помощью чего-то вроде этого, чтобы удалить повторяющиеся косые черты

shopt -s extglob
path="${path//+('/')/'/'}"

и удалить косую черту в конце:

shopt -s extglob
path="${path%+('/')}"

Но опять же, обратите внимание, что в начале имени пути двойная косая черта //fooявляется зарезервированной специальной записью, отличной от одиночной (или тройной и т. д. )косой черты, но вы вряд ли чтобы увидеть это на практике, поэтому я проигнорирую это.

3
28.07.2021, 11:24

В bashдля односимвольных разделителей можно использовать оператор split+glob (, оставляя расширения без кавычек в контекстах списка )после отключения части glob:

string='foo/bar
baz/asd..'

IFS=/
set -o noglob
array=( $string )

Обратите внимание, что он разбивает string='/foo/'на ""и "foo"только (так же, как и при разбиении string='/foo'. Чтобы разделить на "", "foo"и "", вы можете сделать:

IFS=/
set -o noglob
array=( $string'' )

Хотя это затем разбивает string=''на один пустой элемент вместо нулевого элемента.

В zsh(, который не выполняет split+glob при расширении без кавычек, за исключением sh/ kshэмуляции ),вы можете использовать флаг расширения параметра s, который не ограничен одиночными разделителями символов -:

array=( ${(s[/])string} )

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

array=( "${(@s[/])string}" )

Для сохранения пустых элементов. Затем /foo/разбивается на "", "foo"и "", а пустая строка — на нулевой элемент.

Вы можете разделить разделитель, хранящийся в переменной, с помощью:

array=( "${(@ps[$delimiter])string}" )

Флаг pтакже позволяет вводить escape-последовательности, такие как \0, \n, хотя у этих двух есть флаги быстрого доступа:fдля разделения при переводе строки, 0для разделения при нулевом значении (, полезные для разделить вывод find -print0, grep -lZ, sort -z... например,files=( ${(0)"$(grep -lZ pattern -- *)"} )).

В zshвы также можете связать переменную массива со скалярной переменной с заданным одиночным байтом в качестве разделителя. $pathв zshна самом деле является специальным массивом, который связан с $PATHс :в качестве разделителя таким же образом (, вдохновленнымcsh). Вы можете сделать это для любой переменной, такой как:

typeset -T string array /

Для привязки/-разделенного $stringк массиву $array.

5
28.07.2021, 11:24

Теги

Похожие вопросы