Formato diferente no terminal vs em um documento .txt

6

Eu tenho um script que rastreia o tempo.

Quando imprimo minha saída no meu console, recebo isso:

0 Days, 00:00:33

Quando o salve em um arquivo txt, recebo isso:

^[[2K
  0 Days, 00:00:33

Código:

now=$(date +%s)
diff=$(($now - $begin))
mins=$(($diff / 60))
secs=$(($diff % 60))
hours=$(($diff / 3600))
days=$(($diff / 86400))

printf "[2K\r%3d Days, %02d:%02d:%02d" $days $hours $mins $secs
printf "[2K\r%3d Days, %02d:%02d:%02d" $days $hours $mins $secs >> test.txt

De onde vem o ^[[2K ? Eu estou supondo que tem algo a ver com o formato no printf.

Eu li um pouco sobre printf aqui: link . Mas eu não fiquei mais sábio ...

    
por gel 07.10.2016 / 00:50

3 respostas

13

Você tem sequências de controle de escape no comando printf , isto é, printf "[2K..... , ( \e[2K limpa uma linha), que é necessariamente um comando de controle para o terminal, que só pode ser entendido e usado por um dispositivo terminal .

Quando você está executando o script interativamente dentro do terminal, o terminal está interpretando a sequência corretamente. Ao salvar a saída do comando em um arquivo, a sequência está sendo tratada literalmente, pois não há nada para interpretar a sequência.

Agora, se você fizer isso:

cat test.txt

você verá que o terminal está interpretando a sequência corretamente novamente antes da saída ser impressa.

    
por 07.10.2016 / 01:00
5

A sucessão de linhas

printf "[2K\r%3d Days, %02d:%02d:%02d" $days $hours $mins $secs
printf "[2K\r%3d Days, %02d:%02d:%02d" $days $hours $mins $secs >> test.txt

é definido para imprimir informações de tempo em a mesma linha de um terminal. Esse [2K limpa toda a linha (atual) e o \r move o cursor para o início da linha. O efeito é fazer a informação de tempo que muda, apenas parece mudar essa parte da linha.

Percebi que não há nova linha ( \n ) no formato. A pergunta mostra quebras de linha (talvez essas foram adicionadas para maior clareza).

    
por 07.10.2016 / 01:14
4

Você mesmo escreveu, como

[2K

Dependendo do seu terminal, ele entenderá isso como uma instrução para executar alguma ação. Desde que você mencionou "console", você pode consultar a página console_codes(4) man, onde está listado:

ECMA-48 CSI sequences

CSI (or ESC [) is followed by a sequence of parameters, at most NPAR (16), that are decimal numbers separated by semicolons. An empty or absent parameter is taken to be 0. The sequence of parameters may be preceded by a single question mark.

...

K: EL - Erase line

default: from cursor to end of line.
ESC [ 1 K: erase from start of line to cursor.
ESC [ 2 K: erase whole line.

(É bom lembrar que 3 é o mesmo que ESC ).

Portanto, sua sequência de escape é o comando "apagar toda a linha" para este terminal.

A forma portátil (e mais clara) de escrever isso seria

clear_line='tput cr; tput el'
printf "${clear_line}%3d Days, %02d:%02d:%02d" $days $hours $mins $secs

Usar tput significa que, ao gravar em um terminal que não suporta a ação el , ou que a suporta com uma sequência de escape diferente, você obterá a saída apropriada em vez do lixo ininteligível.

P.S. Toda essa aritmética é provavelmente desnecessária, assumindo o GNU date . Se você nunca exceder 7 dias, você pode baixá-lo para

date -u -d "-$begin seconds +3days" '+${clear_line}%w days, %T'

Caso contrário, você ainda precisa calcular $days , mas pode formatar os segundos com %T :

now=$(date +%s)
diff=$(($now - $begin))
days=$(($diff / 86400))
date -u -d "00:00 $diff seconds" '+${clear_line}$days days, %T'
    
por 07.10.2016 / 11:16