2016-12-19 5 views
6

Если бы я хотел, чтобы передать ключи и значения ассоциативного массива в Баш отдельно, и использовать что-то вродеBash ассоциативный массив заказа

./foo.py -k "${!args[@]}" -v "${args[@]}" 

бы они вышли в том же порядке? Мне все равно, что другие пары k = v хранятся, но мне нужно знать, могу ли я рассчитывать на клавиши и значения, выходящие так, что 3-й элемент в массиве ключей фактически является ключом для 3-й элемент в массиве значений.

Я знаю, что ассоциативные массивы «неупорядочены» и что любой порядок, который вы добавляете в массив, не имеет никакого отношения к тому, как они выводятся, но мне интересно, означает ли поведение базового хранилища, что они всегда будут выводиться в том же заказ.

+1

Не ответ, потому что мне пришлось бы проверять код, чтобы обеспечить его. Однако я был бы очень удивлен, если бы это было не так, хотя бы потому, что потребовалось бы, казалось бы, ненужное усилие для создания разных порядков (до тех пор, пока массив не будет изменен между расширениями). – chepner

+0

@chepner: Вы не можете сделать такой вывод. Я не знаю о bash, но на других языках некоторые сохраняют порядок, а некоторые - нет, в зависимости от реализации. В других это может даже измениться между версиями. Например, Tcl - пока (я думаю), версия 8.5 - не гарантирует, что порядок сохранен, но потом он изменил его. – user1934428

+1

Вы утверждаете, что Tcl выполняет что-то вроде хэш-рандомизации при каждом доступе? Это 'array get name' может возвращать другой список каждый раз, когда он вызывается, если' name' вообще не изменяется между вызовами? – chepner

ответ

0

Массивы не являются решением этой проблемы, особенно не являются ассоциативными массивами. Даже если они вышли в том же порядке, у вас будет несколько ключей для одной опции -k , что приведет к синтаксической ошибке. Также массивы a Bashism, и не определены POSIX. Лучшим решением было бы что-то вроде этого:

./foo.py -k key1,key2,key3 -v val1,val2,val3 

Тогда, возможно, Python может разделить строки ввода? Я сделал что-то подобное с POSIX оболочки:

tr , '\n' > keys <<eof 
$1 
eof 
tr , '\n' > vals <<eof 
$2 
eof 
paste -d '\n' keys values | 
while 
    read key 
    read val 
do 
    printf 'key: %s, val: %s\n' "$key" "$val" 
done 

Конечно, это было бы намного проще с Python, как вы могли бы просто разделить строки непосредственно в массивы без использования файлов.

+0

Это на самом деле хорошее использование массивов; их отсутствие является одним из наиболее вопиющих пропусков из спецификации POSIX. – chepner

+0

@chepner Я признаю, что узнал, что массив не POSIX был ударом - вроде как узнал, что синхронный JavaScript устарел –

+0

По сравнению с этим, никакие многострочные лямбды в Python не являются небесами. –

1

Похоже, что да, ключи и значения всегда будут в одном порядке, на основе кода, который я нашел в Bash версии 4.3, assoc.c, доступно here. Клавиши и значения массива извлекаются функциями assoc_keys_to_word_list и assoc_to_word_list соответственно. Обе эти функции делегата assoc_to_word_list_internal, который проходит один и тот же цикл в обоих случаях, и только различает тип элемента, будучи retreived на основе параметра t (строки 482-503):

static WORD_LIST * 
assoc_to_word_list_internal (h, t) 
    HASH_TABLE *h; 
    int t; 
{ 
    WORD_LIST *list; 
    int i; 
    BUCKET_CONTENTS *tlist; 
    char *w; 

    if (h == 0 || assoc_empty (h)) 
    return((WORD_LIST *)NULL); 
    list = (WORD_LIST *)NULL; 

    for (i = 0; i < h->nbuckets; i++) 
    for (tlist = hash_items (i, h); tlist; tlist = tlist->next) 
     { 
    w = (t == 0) ? (char *)tlist->data : (char *)tlist->key; 
    list = make_word_list (make_bare_word(w), list); 
     } 
    return (REVERSE_LIST(list, WORD_LIST *)); 
} 

В дело, которое вам интересно, make_word_list определено в array.c/h. Он просто добавляет новый узел WORD_LIST в существующий связанный список.

Хотя это не гарантирует договорной гарантии, что поведение, которое вы ожидаете, всегда будет поддерживаться, это довольно хороший признак того, что вы можете безопасно использовать свое соглашение о вызове, по крайней мере, на данный момент. Тот факт, что ассоциативные массивы являются Bash-only, делает реализацию более достоверной ссылкой.