Разный формат в терминале и в документе .txt

Для достаточно небольшого вывода, производимого командой, мы можем перенаправить вывод во временный файл и отправить этот временный файл командам в цикле. Это может быть полезно, когда порядок выполнения команд может иметь значение.

Например, это может сделать следующий сценарий:

#!/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
6
07.10.2016, 02:19
3 ответа

В вашей команде printf есть управляющие последовательности, например, printf"\33[2K..... , (\e[2K очищает строку), что обязательно является управляющей командой для терминала, которая может быть понята и выполнена только терминальным устройством.

Когда вы выполняете сценарий интерактивно внутри терминала, терминал правильно интерпретирует последовательность. При сохранении вывода команды в файл последовательность воспринимается буквально, так как интерпретировать последовательность нечем.

Теперь, если вы сделаете:

cat test.txt

вы увидите, что терминал снова правильно интерпретирует последовательность перед выводом на печать.

13
27.01.2020, 20:20

Последовательность строк

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). В вопросе показаны переносы строк (возможно, они были добавлены для ясности).

5
27.01.2020, 20:20

Вы написали это сами, так как

\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'
4
27.01.2020, 20:20

Теги

Похожие вопросы