Ключи ассоциативного массива не хранятся в каком-либо заданном порядке. Обычное решение этой проблемы - иметь второй индексированный массив, содержащий ключи в том порядке, в котором вы хотите их запомнить. Например, массив x
:
declare -a x
test_array[0,0]="1" x[${#x[*]}]='0,0'
test_array[0,1]="A" x[${#x[*]}]='0,1'
...
$ {# x [*]}
- длина массива x
, поэтому каждая строка выше добавляет новую запись {{ 1}} до конца массива x
(индекс 0, затем 1, ...).
Затем вы можете использовать последнюю запись этого массива (с длиной индекса -1), чтобы получить свой ключ и значение:
echo ${x[${#x[*]}-1]}
echo ${test_array[${x[${#x[*]}-1]}]}
Если вы согласны с тем, что весь пакет (переменная/арифметика/расширение команд, подстановка и т. д. )поверх обработки кавычек, это подойдет:
echo '"a b" "x y"' >a.txt
eval "set -- $(<a.txt)"
for b do
printf 'b: %s\n' "$b"
done
b: a b
b: x y
Измените $(<a.txt)
на $(cat a.txt)
, если вы хотите, чтобы он работал в обычной оболочке, а не только вbash
(или других расширенных оболочках, таких как zsh
илиksh
). Вы можете использовать это только в том случае, если уверены, что можете контролировать содержимое a.txt
, в противном случае будет тривиально использовать ваш скрипт с помощью разделения с помощью ;
, расширения команды и т. д.
Однако, если вы просто хотите передать эти аргументы команде, вы можете использовать xargs
, которая будет просто обрабатывать кавычки, не выполняя никаких расширений.:
xargs <a.txt printf 'b: %s\n'
Но xargs
будет работать только с внешними командами, а не с функциями оболочки, будет игнорировать обратную косую черту внутри двойных кавычек, как и внутри одинарных кавычек, и не сможет анализировать многострочные строки.
Если с этими последними ограничениями все в порядке, вы все равно можете использовать xargs
в качестве анализатора котировок через оболочку или массив:
mapfile -t args < <(xargs <a.txt printf '%s\n')
for b in "${args[@]}"; do
printf 'b: %s\n' "$b"
done
Если вместо bash
вы используете ksh93
(ksh93
, если оболочка bash
все равно пытается имитировать ), вы можете использовать опцию -S
встроенной функции read
, которая предназначена для чтения csv (так понимает цитирование стиля csv -):
IFS=" " read -rSA array < a.txt
printf 'a: %s\n' "${array[@]}"
С помощью zsh
вы можете использовать флаг раскрытия параметра z
, который используется для токенизации содержимого переменной, как если бы это был zsh
код (, и поэтому цитирование понимается так же, как zsh
, но не выполнять оценку кода, которую eval
сделал бы )вместе с флагом расширения параметра Q
для удаления одного слоя цитирования:
IFS= read -r line < a.txt
printf 'a: %s\n' "${(Q@)${(z)line}}"
(флаг раскрытия параметра @
предназначен для сохранения пустых элементов, что напоминает поведение ksh
${array[@]}
).
Если a.txt
содержит более одной строки, с zsh
вы можете заменить команду read
на content=$(<a.txt)
, а с ksh93
использовать read
в цикле while
(каждый read
вызов, потенциально читающий более одной строки, если строка в кавычках занимает несколько строк ).