Вы можете анализировать входной поток, используя встроенную программу в Баш read
. Вы можете получить дополнительную информацию с помощью $ help read
. Он обычно разделяет токены, используя пробелы. Если вы предоставили двухстрочный предварительный просмотр того, как выглядит ваш вывод, может быть проще помочь.
Переменные $INSTRUMENT
и $JDAY
должны быть определены до запуска этой команды cat, потому что cat
откроет файл, прежде чем он начнет писать на него.
Если $JDAY
и $INSTRUMENT
, так или иначе должны быть извлечены из каждой строки, вы можете использовать следующий Баш фрагмент кода (предполагая, что строки, считываемые SOCAT выглядеть <INSTRUMENT> <JDAY> <TS> yaddi yadda ...
):
function triage_per_day() {
while read INSTRUMENT JDAY TS REST; do
echo "$TS $REST" >> "${INSTRUMENT}_${JDAY}_RAW";
done
}
triage_per_day < <(socat UDP-RECV:"${UDP_PORT}",reuseaddr -)
Если вы хотите, чтобы получить новые идеи, вам может использовать файловые дескрипторы, чтобы помочь bash работать немного быстрее. Вы можете использовать перенаправления дескрипторов файлов, чтобы сохранить вывод в тот же файл, пока день тот же. Это позволит свести к минимуму количество открываемых файлов и закрытие bash.
function triage_per_day() {
local LAST_JDAY=init
exec 5>&1 # save stdout
exec 1>&2 # echos are sent to stderr until JDAY is redefined
while read INSTRUMENT JDAY TS REST; do
if [[ "$JDAY" != "$LAST_JDAY" ]]; then
# we need to change output file
# send stdout to file in append mode
exec 1>>"${INSTRUMENT}_${JDAY}_RAW"
LAST_JDAY="${JDAY}"
fi
echo "$TS $REST"
done
exec 1>&5 # restore stdout
exec 5>&- # close stdout copy
}
triage_per_day < <(socat UDP-RECV:"${UDP_PORT}",reuseaddr -)
Если вы хотите разметить свои линии над различными символами, чем пробелы, скажем, «» запятая, вы можете локально изменить специальная переменная IFS
:
function extract_ts() {
local IFS=,; # special bash variable: internal-field-separator
# $REST will contain everything after the third token. it is a good
# practice to specify one more name than your last token of interest.
while read TOK1 TS REST; do
echo "timestamp is $TS";
done
}
Если вам нужен любитель обработки каждой строки для извлечения временных меток и других полей вы можете вместо этого выполнять внешние программы (python/perl/cut/awk/grep и т. д.), но это будет намного медленнее, чем просто придерживаться встроенных функций bash, таких как read
или echo
. Если вам нужно это сделать, а скорость - проблема, вы можете подумать о том, чтобы изменить свой сценарий на другой язык, который дает вам необходимую вам выразительность. Вы также можете посмотреть в bash Pattern substitution
в руководстве, если вам нужны необычные регулярные выражения.
function extract_ts() {
# store each line in the variable $LINE
while read LINE; do
TS="$(echo "$LINE" | ...)";
echo "Timestamp is $TS";
done
}
Рекомендуемая практика
Кроме того, я должен отметить, что это хорошая практика, чтобы окружить переменные Баш в двойных кавычках (например, в ответ), если вы собираетесь использовать их в качестве параметров имен файлов. Это особенно верно, если имена содержат пробелы или специальные символы - например, можно ожидать от имени файла, полученного из дат или времени. В тех случаях, когда ваши переменные расширяются до нуля (из-за человеческой ошибки или ошибки программирования), будут отсутствовать позиционные параметры, иногда - плохие последствия.
Рассмотрим:
# copy two files to the directory (bad)
$ cp file1 file2 $MYDIR
Если $MYDIR
не определено, то эта команда суммы, чтобы перезаписать file2 с содержимым file1. Контрастируйте это с cp file1 file2 "$MYDIR"
, который провалится раньше, потому что цель ""
не существует.
Другим источником проблем, которые я вижу в вашем вопросе, являются имена переменных, за которыми следуют символы подчёркивания _
, например $INSTRUMENT
. Они должны быть окружены фигурными фигурными скобками { }
.
INSTRUMENT=6
BAR=49
echo $INSTRUMENT_$BAR # prints '49', but you may have expected 6_49
Поскольку _
являются допустимыми символами в именах переменных, Баш попытается жадностью «клей» тем «_» после того, как INSTRUMENT
, чтобы соответствовать самым длинным допустимое имя переменной возможное, что бы $INSTRUMENT_
. Однако эта переменная не определена и расширяется до пустой строки, поэтому вы остаетесь с остальными, $BAR
. Этот пример может быть правильно переписан как:
INSTRUMENT=6
BAR=49
echo ${INSTRUMENT}_${BAR} # prints 6_49
or even better (avoiding future surprises if values ever change)
echo "${INSTRUMENT}_${BAR}" # prints 6_49
Вы должны прочитать строку в переменную Баш, разобрать переменную, чтобы определить, какой файл он должен записываться, а затем писать. Вы не можете изменить выходной файл на 'cat' после того, как вы запустили' cat'. –
Возможно, название вопроса должно быть изменено на «Как перенаправить вывод команды на несколько файлов с помощью bash на основе данных временной метки?» или что-то в этом роде. –