В bash массивы могут быть либо индексированными либо ассоциативными . Индексированные массивы имеют числовой индекс и (по умолчанию )перебираются в соответствии с числовым порядком их индексов.
Ассоциативный массив (, также известный как hash
илиhashed array
)в bash, может использовать любую строку в качестве индекса (, также известного как key
)-, эта строка может быть числовой (или казаться числовой, в скрипте bash )мало различий, или это может быть любая другая допустимая строка.
Ассоциативные массивы в bash, как и во многих языках, неупорядочены. Если вы просто перебираете массив (, например. без сортировки ключей )вы получите элементы массива в полуслучайном -порядке.
Массивы в bash по умолчанию являются индексированными массивами. Вы можете явно объявить индексированный массив сdeclare -a
(строчными буквами a
. Независимо от того, будет ли declare
d индексироваться или создан как индексированный массив по умолчанию, если вы попытаетесь установить элемент массива с числовым индексом, отличным от -, индекс всегда будет оцениваться как 0
, переопределять или создавать значение (если есть )нулевого элемента массива.
напр.
$ declare -a foo
$ foo[0]=5
$ foo[1]=2
$ declare -p foo
declare -a foo=([0]="5" [1]="2")
Ладно, этого и следовало ожидать. А теперь попробуйте установитьfoo[bar]
:
$ foo[bar]=99
$ declare -p foo
declare -a foo=([0]="99" [1]="2")
Точно так же вы можете объявить массив ассоциативным с помощьюdeclare -A
(обратите внимание на заглавнуюA
). Это заставит массив быть ассоциативным, даже если ВСЕ индексы являются числовыми.
$ unset foo
$ declare -A foo
$ foo[0]=5
$ foo[1]=2
$ foo[bar]=99
$ declare -p foo
declare -A foo=([bar]="99" [0]="5" [1]="2" )
Итак, ответ на ваш вопрос заключается в том, что в примере _1 вы объявили city
ассоциативным массивом . В примере _2 вы этого не сделали, поэтому по умолчанию это массив с индексом .
#### This always works OK, but can't use it in my scenario
foo "1" > >(log) > test_out.txt
foo "2" > >(log) >> test_out.txt
Подстановки процессов здесь кажутся излишними, поскольку следующие перенаправления переопределяют перенаправление stdout прямо в файл. То есть первый должен быть эквивалентен foo "1" > test_out.txt
.
#### This is similar to what I need to do and always fails
exec >test_out.txt
foo "1" > >(log)
foo "2" > >(log)
Здесь, я думаю, проблема в том, что подстановка процесса выполняется асинхронно, и поскольку цикл while read; do echo
медленный, первый log
все еще работает и читает из буферов канала, когда запускается второй. Это похоже на выполнение чего-то вроде echo foo > >(cat; sleep 1; echo hi)
в командной строке, hi
появляется сразу после отображения следующего приглашения. Кроме того, wait
здесь тоже не помогает.
Но я не совсем понимаю, зачем вообще нужны две копии log
? Один бы не сделал:
exec >test_out.txt
exec 9> >(log)
foo "1" >&9
foo "2" >&9
(В моей системе использование cat
вместо while read; do echo
также, по крайней мере, скрывает проблему, так как cat
намного быстрее и читает большими блоками. Но это не значит, что это полностью исправит это, и вы, вероятно, захотите сделать что-то другое, а не просто идентичную копию в log
.)
I should add that I know about external tools which can disable buffering for a command
Если вы имеете в виду такие вещи, как stdbuf -o0
, это помогает только с буферизацией внутри процесса (в библиотеке C ), что, я думаю, здесь не играет роли. Оболочка echo
должна фактически записать данные в ОС перед возвратом.