Как я могу напечатать на стандартный вывод из ловушки, вызванной во время eval

Я ожидал, что следующий скрипт напечатает This is redirected to 'output'. когда я нажимаю Ctrl+C:

#!/bin/bash

trap_function(){
    trap '' EXIT INT TERM
    echo "This is redirected to 'output'."
    touch this_will_exist
}
trap trap_function EXIT INT TERM

eval "sleep 100" &> output

Вместо этого ничего не отображается, и текст переходит в файл output, Как я могу избежать перенаправления изнутри trap_function и текст отображается для пользователя?

echo "This is redirected to 'output'." > /dev/stdout не имеет желаемого эффекта.

Я использую GNU bash версии 4.3.48 в Ubuntu 16.04.5 LTS.

1 ответ

Обходной путь должен иметь eval запустить в подоболочке:

#!/bin/bash

trap_function(){
    trap '' EXIT INT TERM
    echo "This is redirected to 'output'."
    touch this_will_exist
}
trap trap_function EXIT INT TERM

(eval "sleep 100") &> output

Чтобы понять, что происходит, нужно знать, что для того, чтобы bash печатал все, что отправляется на стандартный вывод (который является дескриптором файла 1), он устанавливает дескриптор файла 1 для текущего терминала. Это красиво объяснено здесь https://catonmat.net/bash-one-liners-explained-part-three.

&> output заменяет терминал в файловом дескрипторе 1 и 2 на файл output. Итак, не осталось дескриптора файла, к которому echo "..."можно отправить, что будет отображаться в терминале. Следовательно, у нас есть два возможных решения:

Перенаправление на текущий терминал

Это работает с утилитой tty который возвращает текущий пользовательский терминал.

#!/bin/bash

trap_function(){
    trap '' EXIT INT TERM
    echo "This is redirected to 'output'." &>$(tty)
    touch this_will_exist
}
trap trap_function EXIT INT TERM

eval "sleep 100" &> output

Однако захват этого вывода с помощью оболочки может оказаться невозможным.

Перенаправление через другой файловый дескриптор

Это решение требует, чтобы для текущего терминала был установлен дополнительный файловый дескриптор (например, 123). Мы можем просто использовать то, что уже установлено в файловом дескрипторе 1, прежде чем заменить его на output по 123>&1. Затем мы можем установить файловый дескриптор echo (который является стандартным выводом) к тому, что мы сохранили в файловом дескрипторе 123:

#!/bin/bash

trap_function(){
    trap '' EXIT INT TERM
    echo "This is redirected to 'output'." >&123
    touch this_will_exist
}
trap trap_function EXIT INT TERM

eval "sleep 100" 123>&1 &> output
Другие вопросы по тегам