Я пытаюсь сделать так, чтобы мой stderr
be печатался красным в терминале. Скрипт ниже перенаправляет 2
на пользовательскую 8
ловушку отладки.
exec 9>&2
exec 8> >(
while IFS='' read -r line || [ -n "$line" ]; do
echo -e "${RED}${line}${COLORRESET}"
done
)
function undirect(){ exec 2>&9; } # reset to original 9 (==2)
function redirect(){ exec 2>&8; } # set to custom 8
trap "redirect;" DEBUG
PROMPT_COMMAND='undirect;'
Оно произошло отздесь, с понятным объяснением.
Кажется, работает очень хорошо, однако ввод, не завершающийся новой строкой, вообще не выводится. Цитата автораевангелияснова:
bash> echo -en "hi\n" 1>&2
hi <-- this is red
bash> echo -en "hi" 1>&2
bash> echo -en "hi" 1>&2
bash> echo -en "hi\n" 1>&2
hihihi <-- this is red
Я не могу понять, почему. Содержимое, не являющееся новой строкой, похоже, попадает в какой-то буфер. Оно либо даже не достигает файлового дескриптора 8
, либо каким-то образом не хочет сразу выводиться на печать. Куда оно попадает? redirect
вызывается правильно каждый раз. Также, IFS=''
означает, что нет разделителя, поэтому я не совсем понимаю, почему эхо в in 8
происходит построчно.
Буду очень признателен за исправление ошибки, я прикрепил ссылку на цитируемый ответ к этому вопросу.
Все это решение, как указал Жиль, не совсем идеально. У меня проблемы с чтением, stdin, индикаторами выполнения, не могу ни то, ни su
другое source
. И часто возникают серьезные проблемы, такие как сломанные каналы и неожиданные выходы терминала. Если кто-то попал сюда по моей ссылке, пожалуйста, рассмотрите возможность использованияhttps://github.com/sickill/stderredвместо этого, он стал намного лучше (пока проблем нет) (однако echo bla >&2
остается не красным исоответствующий вопрос закрыт)
решение1
Вы получили частичные строки вывода, как часть той же строки в точке, где была напечатана новая строка. Части строки буферизуются внутри read
,вот что он делает:
Theчитатьутилита должна считывать одну логическую строку из стандартного ввода
Например, это печатается <foobar>
через одну секунду, а не <foo><bar>
.
(echo -n foo ; sleep 1 ; echo bar) | (read x ; echo "<$x>")
Если вы хотите перехватывать вводимые данные частями, меньшими, чем полные строки, вам нужно сделать что-то еще, например, с помощью Perl. Это выведет <foo><bar\n>
(с новой строкой перед последним >
, поскольку в отличие от read
, Perl не обрабатывает последнюю новую строку специально. Не должно иметь значения при раскрашивании.)
(echo -n foo ; sleep 1 ; echo bar) |
perl -e '$|=1; while(sysread STDIN,$a,9999) { print "<$a>"}'
Если у вас есть экспортированные в среду коды управления цветами ( RED
и ), вы можете использовать их из скрипта Perl, как здесь:COLORRESET
perl -e '$|=1; while(sysread STDIN,$a,9999) {print "$ENV{RED}$a$ENV{COLORRESET}"}'
решение2
В Bash вы можете использовать -d
опцию встроенной команды read
, которая определяет символ конца строки. man bash
она гласит следующее:
-d delim The first character of delim is used to terminate the input line,
rather than newline.
Если он не определен, read
ждет \n
появления, чтобы считать строку строкой. Но когда вы используете опцию -d
, вы можете установить NUL
в качестве разделителя. Конечно, вам также нужно завершить ввод NUL.
Пример:
printf "%s\0" $'x\n' y z | while IFS='' read -r -d $'\0' line
do
printf "%s\n" "$line"
done
Выход:
x
y
z
Еще раз, но теперь printf
в курсе while
событий нет \n
.
printf "%s\0" $'x\n' y z | while IFS='' read -r -d $'\0' line
do
printf "%s" "$line"
done
Выход:
x
yz(...)
Я добавил (...)
и это означает, что в конце второй строки нет End-Of-Line. Но текст все равно обрабатывается и печатается.