Для достаточно небольшого вывода, производимого командой, мы можем перенаправить вывод во временный файл и отправить этот временный файл командам в цикле. Это может быть полезно, когда порядок выполнения команд может иметь значение.
Например, это может сделать следующий сценарий:
#!/bin/sh
temp=$( mktemp )
cat /dev/stdin > "$temp"
for arg
do
eval "$arg" < "$temp"
done
rm "$temp"
Тестовый запуск в Ubuntu 16.04 с / bin / sh
в качестве тире
оболочки:
$ cat /etc/passwd | ./multiple_pipes.sh 'wc -l' 'grep "root"'
48
root:x:0:0:root:/root:/bin/bash
В вашей команде printf
есть управляющие последовательности, например, printf"\33[2K.....
, (\e[2K
очищает строку), что обязательно является управляющей командой для терминала, которая может быть понята и выполнена только терминальным устройством.
Когда вы выполняете сценарий интерактивно внутри терминала, терминал правильно интерпретирует последовательность. При сохранении вывода команды в файл последовательность воспринимается буквально, так как интерпретировать последовательность нечем.
Теперь, если вы сделаете:
cat test.txt
вы увидите, что терминал снова правильно интерпретирует последовательность перед выводом на печать.
Последовательность строк
printf "\33[2K\r%3d Days, %02d:%02d:%02d" $days $hours $mins $secs
printf "\33[2K\r%3d Days, %02d:%02d:%02d" $days $hours $mins $secs >> test.txt
определена для печати информации о времени на одной и той же строке терминала. Это \33[2K
очищает всю (текущую) строку, а \r
перемещает курсор в начало строки. Эффект заключается в том, что информация о времени, которая изменяется, кажется, изменяет ту часть строки.
Я заметил, что в формате нет новой строки (\n
). В вопросе показаны переносы строк (возможно, они были добавлены для ясности).
Вы написали это сами, так как
\33[2K
В зависимости от вашего терминала, он будет понимать это как инструкцию для выполнения какого-то действия. Поскольку вы упомянули "консоль", вы можете обратиться к console_codes(4)
man page, где это перечислено:
ECMA-48 CSI последовательности
CSI
(илиESC [
) сопровождается последовательностью параметров, максимум NPAR (16), которые являются десятичными числами, разделенными точкой с запятой. Пустой или отсутствующий параметр принимается за 0. Последовательности параметров может предшествовать один вопросительный знак....
K
: EL - Стереть строкупо умолчанию: от курсора до конца строки.
ESC [ 1 K
: стирание от начала строки до курсора.
ESC [ 2 K
: стирание всей строки.
(Здесь нужно вспомнить, что \033
- это то же самое, что ESC
).
Таким образом, ваша последовательность экранирования является командой "стереть всю строку" для этого терминала.
Переносимый (и более понятный) способ написать это был бы
clear_line=`tput cr; tput el`
printf "${clear_line}%3d Days, %02d:%02d:%02d" $days $hours $mins $secs
Использование tput
означает, что при записи на терминал, который не поддерживает действие el
или поддерживает его с другой последовательностью экранирования, вы получите соответствующий вывод, а не неразборчивый мусор.
P.S. Вся эта арифметика, вероятно, не нужна, если предположить, что GNU date
. Если вы никогда не превышаете 7 дней, вы можете свести это к
date -u -d "-$begin seconds +3days" '+${clear_line}%w days, %T'
В противном случае вам все равно придется вычислять $days
, но вы можете отформатировать секунды с помощью %T
:
now=$(date +%s)
diff=$(($now - $begin))
days=$(($diff / 86400))
date -u -d "00:00 $diff seconds" '+${clear_line}$days days, %T'