#bash #unix #jq
Вопрос:
Я хочу объединить некоторые json в файле с некоторыми json, созданными во время выполнения. у jq, похоже, нет никаких трудностей, если все файлы, переданные ему, находятся здесь-строки или файлы в системе. Но если я попытаюсь смешать типы файлов, кажется, что строки здесь игнорируются, см. Фрагмент ниже:
Два обычных файла:
bash-4.2# echo '{"key":0}' > zero
bash-4.2# echo '{"key":1}' > one
bash-4.2# jq --slurp add zero one
{
"key": 1
}
Обычный файл и здесь-строка (в результате появляется только обычный файл!):
bash-4.2# jq --slurp add zero <<< '{"key":1}'
{
"key": 0
}
Здесь-сначала строка, затем обычный файл (в результате появляется только обычный файл!):
bash-4.2# jq --slurp add <<< '{"key":0,"anotherkey":2}' one
{
"key": 1
}
Одиночная строка здесь (работает нормально):
bash-4.2# jq --slurp add <<< '{"key":0}'
{
"key": 0
}
Две строки здесь (работает нормально): РЕДАКТИРОВАТЬ: Вывод вводит в заблуждение, здесь происходит что-то еще.
bash-4.2# jq --slurp add <<< '{"key":0}' <<< '{"key":1}'
{
"key": 1
}
Я подозреваю, что jq работает просто отлично, и я не знаю, как bash разрешает здесь-строки. Но как бы я отладил это, чтобы улучшить свое понимание?
Примечание: Очень простым обходным путем было бы оценить мой json во время выполнения и создать файл, а затем объединить два файла, как указано выше. Я действительно хочу знать, почему приведенные выше смелые примеры не дают того, чего я ожидал.
Комментарии:
1. Обратите внимание, что herestring-это инструкция для оболочки о том, как настроить stdin. У вас может быть только один stdin и заказ wrt. то, где вы помещаете herestring среди аргументов командной строки, не меняет способа его обработки.
Ответ №1:
После прочтения комментариев это мое понимание:
<<<
сначала оценивается оболочкой и перенаправляет stdin. Если jq
после фильтра не получает позиционных аргументов, он считывает данные из stdin. Поэтому все эти утверждения эквивалентны:
echo "{}" | jq --slurp add
<<< {} jq --slurp add
jq <<< {} --slurp add
jq --slurp <<< {} add
jq --slurp add <<< {}
Если jq
получает позиционные аргументы после фильтра, он интерпретирует их как имена файлов. Он придерживается конвенции о лечении -
как ЗППП.
bash-4.2# echo '{"one":1,"two":1}' > first
bash-4.2# echo '{"three":3}' > third
bash-4.2# jq --slurp add first - third <<< '{"two":2}'
{
"one": 1,
"two": 2,
"three": 3
}
Ответ №2:
Конструкция здесь-строка просто перенаправляет стандартный ввод. Вам отдельно нужно будет указать jq
, чтобы прочитать стандартный ввод, если вы вызовете его таким образом, чтобы он получал аргументы имени файла. Де-факто стандартный способ сделать это-указать -
в качестве входного (псевдо -) имени файла.
Я полагаю, что один из ваших тестовых примеров на самом деле не сработал, и просто выглядел так, как будто он сработал, потому что входные данные были сконструированы таким образом, чтобы не работать.
Комментарии:
1. Для ясности, тестовый пример, который на самом деле не сработал, является последним с двумя строками здесь. Если префикс не содержит файловый дескриптор, отличный от 0,
<<<
оператор перенаправляет стандартный ввод; и если команда содержит несколько перенаправлений, примененных к стандартному вводу, вступает в силу только крайнее правое. Итак, JQ получает{"key":1}
, помещает его в массив и извлекает обратно; он никогда не читает{"key":0}
.2. Это помогло мне провести дальнейшее расследование. Похоже, что jq может правильно считывать данные из stdin, если не передаются никакие другие позиционные аргументы, что ввело меня в заблуждение.
Ответ №3:
Одной из идей было бы использовать подстановку процессов, которая, по сути, предоставляет jq
(временный) файловый дескриптор, с которым он может работать.
Использование awk
для демонстрации идеи файлового дескриптора:
$ awk '{print FILENAME}' <(echo 'abc')
/dev/fd/63
Продемонстрируйте несколько своих примеров:
$ jq --slurp add zero <(echo '{"key":1}')
{
"key": 1
}
$ jq --slurp add zero <(echo '{"keyx":1}')
{
"key": 0,
"keyx": 1
}
$ jq --slurp add <(echo '{"key":0,"anotherkey":2}') one
{
"key": 1,
"anotherkey": 2
}
$ jq --slurp add <(echo '{"key":0}') <(echo '{"key":1}')
{
"key": 1
}
$ jq --slurp add <(echo '{"key":0}') <(echo '{"keyx":1}')
{
"key": 0,
"keyx": 1
}