Временно перенаправить STDOUT в другой файловый дескриптор, но все равно на экран

Я делаю сценарий, который выполняет некоторые команды внутри, и эти команды показывают некоторые выходные данные на STDOUT (а также STDERR как хорошо, но это не проблема). Мне нужно, чтобы мой скрипт генерировал файл.tar.gz для STDOUTпоэтому вывод некоторых команд, выполняемых в скрипте, также STDOUT и это заканчивается неверным файлом.tar.gz в выходных данных.

Итак, короче говоря, можно вывести первые команды на экран (как я все еще хочу увидеть вывод), но не через STDOUT? Также я хотел бы сохранить STDERR нетронутым, поэтому там появляются только сообщения об ошибках.

Простой пример того, что я имею в виду. Это будет мой сценарий:

#!/bin/bash

# the output of these commands shouldn't go to STDOUT, but still appear on screen
some_cmd foo bar
other_cmd baz

#the following command creates a tar.gz of the "whatever" folder,
#and outputs the result to STDOUT
tar zc whatever/

Я пытался возиться с exec и дескрипторы файлов, но я все еще не могу заставить его работать:

#!/bin/bash

# save STDOUT to #3
exec 3>&1

# the output of these commands should go to #3 and screen, but not STDOUT
some_cmd foo bar
other_cmd baz

# restore STDOUT
exec 1>&3

# the output of this command should be the only one that goes to STDOUT
tar zc whatever/

Я думаю, мне не хватает закрытия STDOUT после первого запуска и снова открыть его или что-то, но я не могу найти правильный способ сделать это (сейчас результат такой же, как если бы я не добавил execs

3 ответа

Решение

Стандартный вывод - это экран. Нет разделения между стандартным выводом и "экраном".

В этом случае я бы просто перенаправил stdout на stderr временно с 1>&2 в недрах. Это приведет к тому, что вывод команд будет показан на экране, но не будет в потоке вывода программ.

#!/bin/bash

# the output of these commands shouldn't go to STDOUT, but still appear on screen

# Start a subshell
(
    1>&2                # Redirect stdout to stderr
    some_cmd foo bar
    other_cmd baz
)
# At the end of the subshell, the file descriptors are 
# as they usually are (no redirection) as the subshell has exited.

#the following command creates a tar.gz of the "whatever" folder,
#and outputs the result to STDOUT
tar zc whatever/

Есть ли причина, по которой вам нужно направить вывод этого скрипта во что-то еще? Обычно вы просто записываете tar в файл, используя -f пометить или выполнить перенаправление только для команды tar: tar zc whatever > filename.tar.gz (если вы не поместили его на устройство, такое как лента, или не использовали его в качестве копии).

Не было бы намного проще, если бы вы использовали -f переключиться на команду tar, чтобы сказать tar записывать в файл?

tar zcf whatever.tar.gz whatever/

Если это не делает то, что вы хотите, вам придется перенаправить каждую команду, которая может писать в STDOUT.

some_cmd foo bar 1>&2

Я думаю, что вы ищете какое-то мультиплексирование.

Это простой пример того, как добавить метку времени к каждой строке стандартного вывода: http://www.podciborski.co.uk/programming/perl/add-a-timestamp-to-every-stdout-line/

Вы можете использовать какой-то специальный тег вместо метки времени, чтобы отметить строки журнала. Чем вам придется удалить эти строки на другом конце. Таким образом, использование будет таким:

ssh user@remoteserver the_script.sh | create_tar.sh filename

create_tar.sh должен быть скриптом, который печатает строки с тегом log и перенаправляет другие строки в файл.

Другие вопросы по тегам