Прочитать из файла, затем использовать for для разделения полей, но соблюдать кавычки

Ключи ассоциативного массива не хранятся в каком-либо заданном порядке. Обычное решение этой проблемы - иметь второй индексированный массив, содержащий ключи в том порядке, в котором вы хотите их запомнить. Например, массив 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]}]}
2
21.02.2019, 14:35
2 ответа

Если вы согласны с тем, что весь пакет (переменная/арифметика/расширение команд, подстановка и т. д. )поверх обработки кавычек, это подойдет:

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
2
27.01.2020, 22:02

Если вместо 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вызов, потенциально читающий более одной строки, если строка в кавычках занимает несколько строк ).

1
27.01.2020, 22:02

Теги

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