Вопрос о jq
необходимости явного фильтра при перенаправлении вывода обсуждается во всем Интернете. Но я не могу перенаправить вывод, если он jq
является частью цепочки каналов, даже когда используется явный фильтр.
Рассмотреть возможность:
touch in.txt
tail -f in.txt | jq '.f1'
# in a different terminal:
echo '{"f1":1,"f2":2}' >> in.txt
echo '{"f1":3,"f2":2}' >> in.txt
Как и ожидалось, вывод в исходный терминал из jq
команды:
1
3
Но если я добавлю какой-либо вид перенаправления или конвейера в конец jq
команды, вывод будет молчать:
rm in.txt
touch in.txt
tail -f in.txt | jq '.f1' | tee out.txt
# in a different terminal:
echo '{"f1":1,"f2":2}' >> in.txt
echo '{"f1":3,"f2":2}' >> in.txt
В первом терминале нет вывода, а out.txt пуст.
Я пробовал сотни вариантов, но это неуловимая проблема. Единственный обходной путь, который я нашел , как обнаружил через mosquitto_sub
The Things Network (именно там я и обнаружил проблему), - это обернуть функции tail и jq в сценарий оболочки:
#!/bin/bash
tail -f $1 | while IFS='' read line; do
echo $line | jq '.f1'
done
Потом:
./tail_and_jq.sh | tee out.txt
# in a different terminal:
echo '{"f1":1,"f2":2}' >> in.txt
echo '{"f1":3,"f2":2}' >> in.txt
И, конечно же, вывод:
1
3
Это с последней jq
установленной через Homebrew:
$ echo $SHELL
/bin/bash
$ jq --version
jq-1.5
$ brew install jq
Warning: jq 1.5_3 is already installed and up-to-date
Это (в значительной степени недокументированная) ошибка в jq
моем понимании цепочек труб?
источник
tail -f
для обеспечения непрерывного ввода в программу иtee
для обработки вывода. Если бы вы все еще нуждались в ответе, я бы предложил упростить цепочку, чтобы<in.json jq '.f1' >out.json
вы могли сузить круг причин ее возникновения.tail -f logfile | grep 'foo bar' | awk ...
tail
бит возник из-за попыток разорвать канал (запустить первую команду, выполнить и перенаправить в файл, выполнить это, передать в следующую команду, перенаправить в файл и т. Д.) И запустить его непрерывно в разделах. Это<
хороший инструмент, чтобы иметь в виду, хотя.Ответы:
Вывод из
jq
буферизируется, когда его стандартный вывод передается по конвейеру.Чтобы запросить
jq
очистку выходного буфера после каждого объекта, используйте его--unbuffered
опцию, напримерИз
jq
руководства:источник
Здесь вы видите буферизацию C stdio в действии. Он будет хранить выходные данные в буфере, пока не достигнет определенного предела (может быть 512 байт, или 4 КБ или больше), а затем отправит все сразу.
Эта буферизация автоматически отключается, если stdout подключен к терминалу, но когда он подключен к каналу (как в вашем случае), он включит это поведение буферизации.
Обычный способ отключить / контролировать буферизацию - использовать
setvbuf()
функцию (см. Этот ответ для получения более подробной информации), но это должно быть сделано в самом исходном кодеjq
, так что, возможно, для вас это не практично ...Есть обходной путь ... (Хак, можно сказать.) Есть программа под названием "unbuffer", которая распространяется с "Ожидаемо", которая может создать псевдотерминал и подключить его к программе. Таким образом, несмотря на то,
jq
что все еще будет выполнять запись в канал, он будет думать, что выполняет запись в терминал, и эффект буферизации будет отключен.Установите «ожидаемый» пакет, который должен поставляться с «unbuffer», если у вас его еще нет ... Например, в Debian (или Ubuntu):
Тогда вы можете использовать эту команду:
Смотрите также этот ответ для более подробной информации о "unbuffer", и вы также можете найти страницу справочника здесь .
источник
jq
нативно реализует небуферизованный вывод, поэтому нет необходимости в обходном пути.jq
справочной странице, но через некоторое время мне стало скучно, и я занялся другими делами ... Приятно знать, что что-то подобное происходит! :-)stdbuf -o0
который внедрит код через LD_PRELOAD и сделаетsetvbuf()
за вас волшебный вызов. Работает ли это на macOS, я не уверен.expect
предустановлен на macos,unbuffer
нет. Тем не менее, это часть пакета Homebrew, так что на macos,brew install expect
подойдет.