#linux #bash #shell #ubuntu #script
#linux #bash #оболочка #ubuntu #скрипт
Вопрос:
Я пытаюсь использовать несколько замен процессов в команде BASH, но, похоже, я неправильно понимаю порядок, в котором они разрешаются и перенаправляются друг другу.
Система
Версия Ubuntu 18.04
BASH — GNU bash, версия 4.4.20 (1)-релиз (x86_64-pc-linux-gnu)
Проблема
Я пытаюсь перенаправить вывод команды в tee
, перенаправить это в ts
(добавив временную метку), а затем перенаправить это в split
(разделив вывод на отдельные файлы). Я могу перенаправить выходные данные в tee
и ts
, но при перенаправлении в split
я сталкиваюсь с проблемой.
Мои попытки
command >(tee -a >(ts '[%Y-%m-%d %H:%M:%S]' > tempfile.txt))
— это перенаправит вывод в процесс подстановки tee
, затем перенаправит на процесс подстановки ts
и добавит временную метку, а затем перенаправит на tempfile.txt это то, чего я ожидал бы
command >(tee -a >(ts '[%Y-%m-%d %H:%M:%S]' >(split -d -b 10 -)))
— это ничего не дает, хотя я бы надеялся, что результатом была бы куча 10-байтовых файлов с временными метками в разных строках.
Чтобы продолжить тестирование, я попытался , по-видимому, это не имеет значения из-за нового результата, который я получил — см. Редактирование внизу echo
вместо этого посмотреть, что произойдет command >(tee -a >(ts '[%Y-%m-%d %H:%M:%S]' >(echo)))
— печать с начальных tee
отпечатков (как и должно быть), но echo
печатает пустую строку
command >(tee -a >(ts '[%Y-%m-%d %H:%M:%S]') >(split -d -b 10 -))
— Это печатает команду с меткой времени (как tee
и ts
должно быть) и, кроме того, создает 10-байтовые файлы с выводом команды (без метки времени на них). — это то, чего я ожидал, и имеет смысл, поскольку тройник перенаправляется на обе замены процесса отдельно, в основном это была проверка на вменяемость
Что, я думаю, происходит
Из того, что я могу сказать >(ts '[%Y-%m-%d %H:%M:%S]' >(split -d -b 10 -))
(и, они сначала решаются как самостоятельная полная и отдельная команда. Таким образом >(ts '[%Y-%m-%d %H:%M:%S]' >(echo))
если уж на то пошло) split
(и echo
) получают пустой вывод, из ts
которого сам по себе не выводится. Только после этого фактическая команда разрешается и отправляет свои выходные данные на замену tee
.
Это не объясняет, почему command >(tee -a >(ts '[%Y-%m-%d %H:%M:%S]' > tempfile.txt))
это работает, поскольку по этой теории tee
само по себе не имеет выходных данных, поэтому ts
должно получать не входные данные, а также должно выводить пробел.
Все это означает, что я не совсем уверен, что происходит. Я думаю, что это связано с порядком разрешения замен процессов и тем, как происходят перенаправления, но для меня ничего не имеет смысла в том, как именно это происходит.
Чего я хочу
По сути, я просто хочу понять, как заставить command >(tee -a >(ts '[%Y-%m-%d %H:%M:%S]' >(split -d -b 10 -)))
работать так, как кажется. Мне нужно, чтобы выходные данные команд отправлялись в процесс substitution tee
, который отправит его в процесс substitution ts
и добавит временные метки, которые будут отправлены, split
и разделит вывод на несколько небольших файлов.
Спасибо за ваше время и любую помощь, которую вы можете предоставить.
* Редактировать — я только что попробовал command > >(echo)
и увидел, что вывод пустой, что не то, что я ожидал (я ожидал echo
получить, а затем вывести вывод команды). Я думаю, что я просто очень не понимаю, как работает замена процесса на данный момент
Комментарии:
1. Почему бы и нет
command | ts '[%Y-%m-%d %H:%M:%S]' | split -d -b 10 -
?2. Я не упоминал об этом, но фактическая команда, которую я использую, разделяет stdout и stderr, и я думаю, что это не позволяет использовать конвейер (но, может быть, я ошибаюсь?). Также я бы предпочел (хотя это скорее «приятно иметь») использовать
tee
, чтобы мой вывод также отображался на экране одновременно.3.
echo
игнорирует его ввод. Возможно, вы думаете оcat
, который считывает свои входные данные и записывает все в свои выходные данные.4. @WilliamPursell спасибо. да, я заметил это, пытаясь поэкспериментировать с cat и увидев, как это работает. Я никогда не понимал, что это так, хотя это echo игнорирует ввод при передаче по каналу.
5. Если вы хотите, чтобы поток ошибок также попадал в канал
ts
, просто сделайтеcommand 2>amp;1 | ts ... | split ...
Ответ №1:
Вы можете разделить отправку потока ошибок из команды на другой конвейер, отличный от выходного, если это необходимо:
{ { cmd 2>amp;3 | ts ... | split; } 3>amp;1 >amp;4 | ts ... | split; } 4>amp;1
Это отправляет выходные cmd
данные в первый конвейер, в то время как поток ошибок из cmd
поступает во 2-й конвейер. Файловый дескриптор 3 введен для разделения потоков ошибок ts
и split
разделения, но это может быть нежелательным. fd 4 вводится для split
предотвращения потребления выходных данных вторым конвейером, и это может оказаться ненужным ( split
например, если не производит никаких выходных данных).
Комментарии:
1. я не уверен на 100%, что это работает с потоком ошибок, потому что я не могу проверить это на данный момент, но в остальном, похоже, работает как шарм! Спасибо! Я просто добавил опцию tee, чтобы она также выводила на экран выходные данные, поэтому в итоге я получил
{ { cmd 2>amp;3 | ts '[%Y-%m-%d %H:%M:%S]' | tee -a >(split -d -b 10 - out); } 3>amp;1 >amp;4 | ts '[%Y-%m-%d %H:%M:%S]' | tee -a >(split -d -b 10 - e rr); } 4>amp;1
Ответ №2:
Одна вещь, которую вы могли бы сделать, если вы действительно хотите, чтобы одна команда перенаправляла stdin / stderr на отдельный ts|tee|split
, это
command 1> >(ts '[%Y-%m-%d %H:%M:%S]' | tee -a >(split -d -b 10 -)) 2> >(ts '[%Y-%m-%d %H:%M:%S]' | tee -a >(split -d -b 10 -))
Но недостатком является то, что tee печатается только после печати приглашения. Вероятно, есть способ избежать этого, дублируя файловые дескрипторы, но это лучшее, что я мог придумать.
Комментарии:
1. … «Все еще ожидаете ввода»? Это зависит от того, что у вас
command
есть; знаем ли мы, что используемая команда вообще ожидает ввода?2. Я подозреваю, что вы видите не что-то «ожидающее ввода», а вместо этого отложенные записи, поступающие на консоль после печати приглашения, поэтому приглашение смешивается с выводом — таким образом, нажатие enter просто выводит второе приглашение.
3. @CharlesDuffy ах да, футболка печатается после печати приглашения.
4. … что касается того, как этого можно избежать — я исторически написал код, который используется
flock -s
для создания общей блокировки для каждой из ваших команд, участвующих в выполнении записи, а затемflock -x
для ожидания завершения всех этих процессов (поскольку эксклюзивная блокировка может быть создана только после закрытия всех общих блокировок).5. (кстати, на самом деле неправильно говорить «tee печатает только после запроса» — tee может и часто будет печатать раньше, в зависимости от того, сколько содержимого есть и сколько времени
command
требуется для выполнения; просто не гарантируется, что он также не продолжит печатать содержимоеcommand
, из которого вышел, и родительскую оболочкуобнаружил это и напечатал приглашение).
Ответ №3:
Это:
ts '[%Y-%m-%d %H:%M:%S]' >(split -d -b 10 -)
расширяет имя файла , сгенерированное подстановкой процесса в командной строке ts
, так что запускается что — то вроде ts '[%Y-%m-%d %H:%M:%S]' /dev/fd/63
. ts
затем пытается открыть fd
то, что переходит split
к чтению входных данных оттуда, вместо чтения из исходного stdin.
Вероятно, это не то, что вы хотите, и на моей машине я получил несколько копий ts
и split
застрял в фоновом режиме во время тестирования. Возможно, они успешно подключены друг к другу, что может объяснить отсутствие сообщений об ошибках.
Вы, вероятно, хотели написать
ts '[%Y-%m-%d %H:%M:%S]' > >(split -d -b 10 -)
^
с перенаправлением на процесс подстановки.
Тем не менее, вы могли бы просто использовать канал между ts
и split
.