Como posso converter para saída stderr maiúscula, mas não stdout?

1

Estou usando o rsync para fazer backup de alguns arquivos:

rsync -PaSh --stats --delete -e "-i key -p XXXX" "/source/" [email protected]:/destination/ 2> output.txt | grep -e 'bytes  received' -e 'total bytes' -e files -e 'total file size:' >> output.txt

porque existem milhares de arquivos, só quero ver erros e um resumo no final.

O comando acima mostra isso:

rsync: delete_file: unlink(test/test.txt) failed: Permission denied (13)
Number of files: 12 (reg: 10, dir: 2)
Number of created files: 0
Number of regular files transferred: 0
sent 382 bytes  received 137 bytes  41.52 bytes/sec

Eu quero converter em maiúsculas apenas os erros (para chamar a atenção para eles) e deixar o resumo inalterado.

Então ficaria assim:

RSYNC: DELETE_FILE: UNLINK(TEST/TEST.TXT) FAILED: PERMISSION DENIED (13)
Number of files: 12 (reg: 10, dir: 2)
Number of created files: 0
Number of regular files transferred: 0
sent 382 bytes  received 137 bytes  41.52 bytes/sec

Como posso conseguir isso?

Obrigado

    
por NoExpert 06.01.2018 / 12:47

3 respostas

3

Você pode efetivamente trocar stdin e stdout com a ajuda de um descritor de arquivo temporário (fd 3 aqui):

cmd 3>&2 2>&1 1>&3- | tr '[:lower:]' '[:upper]'

Isso indica que "aponte o novo fd no local stderr , aponte stderr onde stdout aponta, aponte stdout para onde stderr apontou originalmente "... fácil, certo? :)

Ou, em outras palavras: agora o stderr do cmd irá percorrer o canal como stdout enquanto o stdout original foi redirecionado para stderr . E o comando tr fará a conversão de letras maiúsculas.

Atualização: Embora você tenha aceitado a resposta acima, sua lista de desejos incluiu a capacidade de manipular stdout e stderr simultaneamente. Então, vamos tentar resolver isso ... tendo em mente que estamos nos deparando com algumas coisas que eu não faço com frequência!

Uma troca simples de stdout / stderr não fará nada de útil. Com ou sem o swap, você não pode usar dois fluxos diferentes através de um único pipeline. A primeira coisa que vem à mente como alternativa é usar FIFOs (named pipes):

mkfifo /tmp/fifo1 /tmp/fifo2

# run the key command in the background, in a subshell to suppress
# job control messages (e.g. "[1] 12345" and "[1]+ Exit ...")
( cmd > /tmp/fifo1 2> /tmp/fifo2 & )

# concatenate tr/stderr and grep/stdout using process substitution
# (I'm assuming the summary information occurs at the end of rsync output)
cat <(cat /tmp/fifo2 | tr '[:lower:]' '[:upper:]') <(grep ... /tmp/fifo1) 

rm -f /tmp/fifo1 /tmp/fifo2

Você poderia realmente colocar tudo isso em uma linha, se assim inclinado!

mkfifo /tmp/fifo1 /tmp/fifo2; (cmd > /tmp/fifo1 2> /tmp/fifo2 &); cat <(cat /tmp/fifo2 | tr '[:lower:]' '[:upper:]') <(grep ... /tmp/fifo1); rm -f /tmp/fifo1 /tmp/fifo2

Meus testes de sanidade estão funcionando bem, então experimente.

    
por 06.01.2018 / 13:17
1

Para converter stderr para maiúsculas sem alterar onde stdout e stderr vão para:

{ rsync ... 2>&1 >&3 3>&- | perl -Mopen=locale -pe '$_=uc' >&2 3>&-; } 3>&1

Isso é duplicado no stdout original para o fd 3, para que possamos restaurá-lo por rsync .

Aqui, use perl em vez de tr , pois ele fornece melhores resultados para itens como Stéphane - > STÉPHANE ( STéPHANE com GNU tr ) ou traffic - > TRAFFIC ( TRAffiC com o GNU tr / sed / awk).

Note que agora que stderr passa por um pipe, isso pode afetar a ordem relativa das mensagens stdout e stderr, já que as mensagens stderr estão sendo atrasadas.

Veja

para algumas outras abordagens que você pode achar útil.

    
por 07.01.2018 / 08:37
0

Use o comando abaixo em vez do seu comando. Eu adicionei um comando extra depois de redirecionar o erro para output.txt

Eu adicionei sed -i "s /.*/ \ U & g" output.exe Como testado seus trabalhos bem

rsync -PaSh --stats --delete -e "-i key -p XXXX" "/source/" [email protected]:/destination/ 2> output.txt ;sed -i  "s/.*/\U&/g" output.txt| grep -e 'bytes  received' -e 'total bytes' -e files -e 'total file size:' >> output.txt  
por 06.01.2018 / 14:01

Tags