Зациклите кортежи в Bash? - PullRequest
68 голосов
/ 15 марта 2012

Возможно ли зациклить кортежи в bash?

Например, было бы здорово, если бы сработало следующее:

for (i,j) in ((c,3), (e,5)); do echo "$i and $j"; done

Есть ли обходной путь, который позволяет мне циклически перебирать кортежи?

Ответы [ 9 ]

71 голосов
/ 15 марта 2012
$ for i in c,3 e,5; do IFS=","; set -- $i; echo $1 and $2; done
c and 3
e and 5

Об этом использовании set (из man builtins):

Все аргументы, оставшиеся после обработки опций, рассматриваются как значения для позиционных параметров и присваиваются по порядку $ 1, $ 2, ... $ n

IFS="," устанавливает разделитель полей, поэтому каждый $i будет сегментирован на $1 и $2 правильно.

Через этот блог .

Редактировать: более правильная версия, предложенная @SLACEDIAMOND:

$ OLDIFS=$IFS; IFS=','; for i in c,3 e,5; do set -- $i; echo $1 and $2; done; IFS=$OLDIFS
c and 3
e and 5
16 голосов
/ 04 апреля 2016

Я считаю, что это решение немного чище, чем другие, которые были отправлены, h / t для это руководство по стилю bash для иллюстрации того, как чтение может использоваться для разделения строк в разделителе и назначения ихотдельные переменные.

for i in c,3 e,5; do 
    IFS=',' read item1 item2 <<< "${i}"
    echo "${item1}" and "${item2}"
done
7 голосов
/ 15 марта 2012
c=('a' 'c')
n=(3    4 )

for i in $(seq 0 $((${#c[*]}-1)))
do
    echo ${c[i]} ${n[i]}
done

Может быть, иногда будет удобнее.

Для объяснения части ugly, как отмечено в комментариях:

seq 0 2 производит последовательность чисел 0 1 2. $ (cmd) является подстановкой команды, поэтому для этого примера вывод seq 0 2, который является числовой последовательностью. Но какова верхняя граница, $((${#c[*]}-1))?

$ ((что-то)) является арифметическим расширением, поэтому $ ((3 + 4)) равно 7 и т. Д. Наше выражение равно ${#c[*]}-1, поэтому что-то - 1. Довольно просто, если мы знаем, что такое ${#c[*]}.

c - это массив, c [*] - это просто весь массив, $ {# c [*]} - это размер массива, равный 2 в нашем случае. Теперь мы откатим все назад: for i in $(seq 0 $((${#c[*]}-1))) равно for i in $(seq 0 $((2-1))) равно for i in $(seq 0 1) равно for i in 0 1. Потому что последний элемент в массиве имеет индекс, который является длиной массива - 1.

6 голосов
/ 05 марта 2018

Используйте ассоциативный массив (также известный как словарь / hashMap):

declare -A pairs=(
  [c]=3
  [e]=5
)
for key in "${!pairs[@]}"; do
  value="${pairs[$key]}"
  echo "key is $key and value is $value"
done

Работает для bash4.0 +.


Если вы считаете, что в один прекрасный день вам могут понадобиться тройкивместо пар можно использовать более общий подход:

animals=(dog cat mouse)
declare -A sound=(
  [dog]=barks
  [cat]=purrs
  [mouse]=cheeps
)
declare -A size=(
  [dog]=big
  [cat]=medium
  [mouse]=small
)
for animal in "${animals[@]}"; do
  echo "$animal ${sound[$animal]} and it is ${size[$animal]}"
done
6 голосов
/ 15 марта 2012
$ echo 'c,3;e,5;' | while IFS=',' read -d';' i j; do echo "$i and $j"; done
c and 3
e and 5
5 голосов
/ 07 сентября 2018

На основе ответа, данного @ eduardo-ivanec без установки / сброса IFS, можно просто сделать:

for i in "c 3" "e 5"
do
    set -- $i
    echo $1 and $2
done

Выход:

c and 3
e and 5
2 голосов
/ 05 ноября 2016

Использование GNU Parallel:

parallel echo {1} and {2} ::: c e :::+ 3 5

Или:

parallel -N2 echo {1} and {2} ::: c 3 e 5

Или:

parallel --colsep , echo {1} and {2} ::: c,3 e,5
0 голосов
/ 18 марта 2019
do echo $key $value
done < file_discriptor

например:

$ while read key value; do echo $key $value ;done <<EOF
> c 3
> e 5
> EOF
c 3
e 5

$ echo -e 'c 3\ne 5' > file

$ while read key value; do echo $key $value ;done <file
c 3
e 5

$ echo -e 'c,3\ne,5' > file

$ while IFS=, read key value; do echo $key $value ;done <file
c 3
e 5
0 голосов
/ 15 марта 2012

Немного сложнее, но может быть полезно:

a='((c,3), (e,5))'
IFS='()'; for t in $a; do [ -n "$t" ] && { IFS=','; set -- $t; [ -n "$1" ] && echo i=$1 j=$2; }; done
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...