Что изменяет выполнение docker exec внутри подпроцесса в выводе?

Вопрос или проблема

Если я выполню команду docker exec -it stupefied_poitras bash -c 'time date', то получу следующий вывод

Чт Сен 19 05:02:04 UTC 2024

real    0m0.000s
user    0m0.000s
sys     0m0.000s

Если я выполню команду A=$(docker exec -it stupefied_poitras bash -c 'time date') && echo $A, то получу

 sys 0m0.000ss02:09 UTC 2024

Если я выполню команду A=$(docker exec -it stupefied_poitras bash -c 'time date' 1>&2) && echo $A, то получу

Чт Сен 19 05:14:59 UTC 2024

real    0m0.002s
user    0m0.001s
sys     0m0.000s

Меня довольно сильно сбивает с толку второй вывод. Почему включена только последняя строка stderr и откуда берется возврат каретки (при условии, что это причина перезаписи)?

Кроме того, меня также смущает еще два других поведения:
Это поведение присутствует только если я использую docker exec. То есть A=$(bash -c 'time date') && echo $A не показывает этого (хотя в этом случае вывод времени предшествует выводу даты). Почему оно перевернуто?

Если я перенаправлю stderr на stdout (2>&1) в третьем случае, то я получаю тот же испорченный вывод, как и во втором случае. Почему это имеет значение, перенаправляю ли я stdout на stderr или наоборот?

Ответ или решение

Когда вы выполняете команду docker exec, важным аспектом является то, как наследуются стандартные потоки ввода-вывода при выполнении команд внутри контейнера. Разберем ваши вопросы по порядку.

  1. Разница в выводе между разными командами:

    • Когда вы выполняете docker exec -it stupefied_poitras bash -c 'time date', вы получаете ожидаемый вывод, где первый вывод — это результат команды date, а последующие строки — результат выполнения команды time, который включает в себя время выполнения.
    • В случае A=$(docker exec -it stupefied_poitras bash -c 'time date') && echo $A, вывод помещается в переменную A, но здесь происходит перезапись stdout и stderr. На самом деле time выводит данные в stderr, а так как переменная A захватывает stdout, делает это неправильно: вывод date и время выполнения перемешиваются, что и приводит к неожиданному выводу. Мы видим только последние 2 символа времени, что может быть связано с тем, что вывод time помещается в stderr, и поведение зависит от консольного вывода (символы могут перезаписывать друг друга).
  2. Почему поведение docker exec отличается от локального выполнения:

    • В случае A=$(bash -c 'time date'), все выполняется в одном и том же контексте и выводы stderr и stdout идут в порядке их вызова, поэтому вы видите сначала date, а затем time. В случае docker exec, контейнер создает отдельный процесс, и потоки вывода могут обрабатываться отдельно, что может привести к переполнению буфера или изменению порядка вывода.
  3. Перенаправление stderr в stdout:
    • Когда вы используете A=$(docker exec -it stupefied_poitras bash -c 'time date' 2>&1) && echo $A, вы объединяете stderr и stdout, что дает более предсказуемый результат, так как оба потока теперь идут в одну и ту же переменную. Однако при этом могут возникнуть те же проблемы с порядком вывода и перезаписью, из-за чего иногда вывод может казаться «разваленным».

Суммируя, поведение, которое вы наблюдаете, связано с различиями в контексте выполнения и способах обработки потоков ввода-вывода, а также с тем, как контейнеры Docker управляют этими потоками. Чтобы предотвратить проблемы с порядка вывода, вы можете либо явно перенаправлять потоки, как в третьем примере, либо использовать другие подходы для обработки вывода (например, записывать результаты в файлы и затем считывать эти файлы, хотя это может быть менее удобно).

Оцените материал
Добавить комментарий

Капча загружается...