Я не совсем понимаю команду, но ваше описание выглядит так, как будто это работа для именованных каналов. Чтобы прояснить эту концепцию, мой пример использует четыре из них. С правильными заменами вы можете уменьшить это число до двух, я думаю, возможно даже до одного; но пока давайте будем простыми.
mkfifo pre-audio-pipe pre-video-pipe audio-pipe video-pipe # creating pipes
(reading commands) | mbuffer -p 1 -m 5G | tee pre-audio-pipe > pre-video-pipe # splitting
Этот процесс заполнит все буферы, созданные для двух именованных каналов, затем будет ожидать чтения этих данных в другом месте.
"В другом месте" находится в другой консоли:
<pre-audio-pipe (isolate audio) | (process audio) > audio-pipe
и в еще одной консоли:
<pre-video-pipe (isolate video) | (process video) > video-pipe
Снова эти две команды будут ждать, пока мы не прочитаем некоторые данные из каналов. В финальной консоли:
ffmpeg -i video-pipe -i audio-pipe (doing final conversion)
Вы можете столкнуться с блокировкой в случае, если последняя команда хочет прочитать один поток впереди другого. Я не знаю, насколько это вероятно. Дополнительные буферы могут быть полезны, чтобы избежать этого. Моей первой попыткой было бы удалить mbuffer
(до tee
) и вставить два независимых буфера между соответствующими (isolate)
и (process)
.
После того, как все это сделано:
rm pre-audio-pipe pre-video-pipe audio-pipe video-pipe # cleaning
редактировать
Из комментария ОП:
Вы видите какой-либо шанс реализовать решение без использования отдельных именованных каналов?
Я думал о сопроцессах (coproc
встроенный), но я их мало знаю. Есть исчерпывающий ответ о них. Ищите фразу "почему они не так популярны". Оттуда:
Единственное преимущество использования coproc
заключается в том, что вам не нужно очищать эти именованные каналы после использования.
Я полностью согласен. Посмотрите на пример там - это в основном ваш случай с потоком данных раздвоенным, а не двусторонним. В примере используются оболочки, отличные от bash
но по моему опыту в bash
это было бы также ужасно.
В идеале, это была бы однострочная команда, работающая только с неназванными каналами, поскольку задание должно быть запущено с "экономическим усилием" из командной строки.
Шутки в сторону? Со всеми этими (doing some encoding here)
расширены? По моему мнению, независимо от того, используете ли вы именованные или безымянные каналы, "экономическим усилием" здесь будет написание сценария, даже если это одноразовая работа. Сравнивая длинный однострочный и эквивалентный хорошо написанный скрипт, я считаю, что последний легче отлаживать.
Но так как вы попросили однострочник, вы получите его, но с именованными каналами. Моя идея поддерживать именованные каналы - создать для них временный каталог. Общая концепция:
my_temp=`mktemp -d` ; pre_audio_pipe="${my_temp}/pre-audio-pipe" ; pre_video_pipe="${my_temp}/pre-video-pipe" ; audio_pipe="${my_temp}/audio-pipe" ; video_pipe="${my_temp}/video-pipe" ; mkfifo "$pre_audio_pipe" "$pre_video_pipe" "$audio_pipe" "$video_pipe" ; (reading commands) | tee "$pre_audio_pipe" > "$pre_video_pipe" & <"$pre_audio_pipe" (isolate audio) | mbuffer -p 1 -m 1G | (process audio) > "$audio_pipe" & <"$pre_video_pipe" (isolate video) | mbuffer -p 1 -m 4G | (process video) > "$video_pipe" & ffmpeg -i "$video_pipe" -i "$audio_pipe" (doing final conversion) ; rm -rf "$my_temp"
В соответствии с этим ответом вы, вероятно, можете поместить его в одну командную строку, даже после того, как вы углубитесь в команду и развернете все эти (do something)
заполнители.
Хорошо, форма с одной строчкой должна была показать вам, насколько это неудобно. Та же концепция, что и сценарий:
#!/bin/bash
my_temp=`mktemp -d`
pre_audio_pipe="${my_temp}/pre-audio-pipe"
pre_video_pipe="${my_temp}/pre-video-pipe"
audio_pipe="${my_temp}/audio-pipe"
video_pipe="${my_temp}/video-pipe"
mkfifo "$pre_audio_pipe" "$pre_video_pipe" "$audio_pipe" "$video_pipe" #creating actual pipes
# Main code here.
# Notice we put few commands into the background.
# In this example there are two separate mbuffers.
(reading commands) | tee "$pre_audio_pipe" > "$pre_video_pipe" & # splitting
<"$pre_audio_pipe" (isolate audio) | mbuffer -p 1 -m 1G | (process audio) > "$audio_pipe" &
<"$pre_video_pipe" (isolate video) | mbuffer -p 1 -m 4G | (process video) > "$video_pipe" &
ffmpeg -i "$video_pipe" -i "$audio_pipe" (doing final conversion)
# Then cleaning:
rm -rf "$my_temp"