[resolvido] comando sed

Iniciado por sigur, 30 de Maio de 2012, 16:37

tópico anterior - próximo tópico

irtigor

É um comando de teste embutido no bash (adotado do ksh e presente no zsh também), é mais robusto que o "[" (dá pra fazer comparação com expressão regular, por exemplo).

Se o seu script vai depender do bash, eu não vejo motivos pra não usá-lo.

sigur

Bem, acho que estou terminando. Está ficando legal. Optei por não exibir a saída do pdflatex, pois gera muita coisa na tela. Só que se der erro, daí trava tudo.

Aconteceu agora pouco. Havia um erro dentro do .tex, erro de TeX mesmo, comando errado. Daí o script parou e eu não consegui finalizar. Tive que fechar a janela do terminal.

Veja como está ficando:
## generate list of tex files to use with \import command
#rm *.aux 2> /dev/null
#[[ $? -eq 1 ]] && echo "nao tem nenhum aux"
#for i in *.aux; do
#   [[ -f "$i" ]] || continue
#   rm "$i"
#done

echo  "| ###########################"
echo "| removendo arquivos temporários para inciar processo..."
rm texfiles/*.aux 2> /dev/null
rm *.aux 2> /dev/null
rm *.log 2> /dev/null
rm *.toc 2> /dev/null

echo "| removendo arquivos antigos de índice para importação..."
rm indice-*.tex 2> /dev/null

#if [ -f indice-comm.tex ];
#then
#rm indice-comm.tex
#fi

echo "| criando arquivos novos de índice para importação..."
for file in texfiles/comm*.tex ; do
#grep -E '^.title|^.author' $file >> indice-comm.tex
echo -e "\\import{$file}\n" >>  indice-comm.tex
sed -e 's;\.tex;;' -i indice-comm.tex
done
echo "| arquivo indice-comm.tex criado"

#if [ -f indice-talk.tex ];
#then
#rm indice-talk.tex
#fi

for file in texfiles/talk*.tex ; do
#grep -E '^.title|^.author' $file >> indice-talk.tex
echo -e "\\import{$file}\n" >>  indice-talk.tex
sed -e 's;\.tex;;' -i indice-talk.tex
done
echo "| arquivo indice-talk.tex criado"

#if [ -f indice-poster.tex ];
#then
#rm indice-poster.tex
#fi

for file in texfiles/poster*.tex ; do
#grep -E '^.title|^.author' $file >> indice-poster.tex
echo -e "\\import{$file}\n" >>  indice-poster.tex
sed -e 's;\.tex;;' -i indice-poster.tex
done
echo "| arquivo indice-poster.tex criado"

echo "|"
echo "| compilando caderno.tex duas vezes com pdflatex..."
echo "| ..."
echo "| ..."
pdflatex caderno.tex 1> /dev/null
pdflatex caderno.tex 1> /dev/null
echo "| arquivo caderno.pdf criado"
echo "| "
echo "| removendo arquivos temporários para finalizar processo..."
rm texfiles/*.aux 2> /dev/null
rm *.aux 2> /dev/null
rm *.log 2> /dev/null
rm *.toc 2> /dev/null
echo "| PRONTO!"
echo  "| ###########################"

irtigor

Você pode colocar uma cadeia condicional, tipo


pdflatex caderno.tex 1> /dev/null || exit $?


Se o pdflatex falhar (código de estado diferente de 0) o comado exit é executado. Também dê uma olhada no trap.

No lugar de fechar o terminal, você pode apertar ctrl+c pra finalizar o programa em execução no primeiro plano.

sigur

Citação de: irtigor online 08 de Junho de 2012, 13:09
Você pode colocar uma cadeia condicional, tipo


pdflatex caderno.tex 1> /dev/null || exit $?


Se o pdflatex falhar (código de estado diferente de 0) o comado exit é executado. Também dê uma olhada no trap.

No lugar de fechar o terminal, você pode apertar ctrl+c pra finalizar o programa em execução no primeiro plano.

hum, não deu certo. coloquei um comando \aleph no meu caderno.tex, de modo que o pdflatex irá reclamar, pois não usei $\aleph$ (não sei se você usa tex). Mas o problema foi o mesmo, parou e nada. Apertei ctrl+c mas não deu, só imprimiu no terminal ^C, ou seja, tem algo estranho.

Talvez seja o modo de como o pdflatex trabalha. Na verdade, quando encontra um erro no tex, ele para e espera o user tomar uma atitude. Rodando pdflatex direto pelo terminal, o erro é
! Missing $ inserted.
<inserted text>
                $
l.527 \aleph
           
?


ou seja, a execução para. Para interromper, posso usar x <enter> e daí volto pro prompt.

irtigor

Olhei o manual, se você usar a opção "-halt-on-error" o que eu falei deve funcionar.

sigur

Citação de: irtigor online 08 de Junho de 2012, 14:10
Olhei o manual, se você usar a opção "-halt-on-error" o que eu falei deve funcionar.

Opa! Perfeito. Forcei um erro e agora ele não trava. O processo do pdflatex vai até o fim, com as consequências de se ter um erro, claro. Mas o script termina e volta pro prompt.

Só preciso arrumar um modo de fazer algo aparecer na tela, dizendo que o processo foi interrompido, pois as msg estão sendo as mesmas, dando a impressão de que tudo está certo.

Será que tem como testar se a saída de erros do pdflatex é vazia ou não? Não sei se funciona como no comando cp, por exemplo, onde mostra na tela uma msg de erro quando não copia.

Vou fuçar um pouco. Mas uma coisa é certa: se eu pedir pra deletar o pdf logo de cara, se der erro não será criado um pdf, daí eu sei que tem problema, mesmo as msg sendo as mesmas.

Valeu!

irtigor

A variável $? guarda o ultimo sinal. "0" significa que o programa rodou certo, os outros números indicam os vários tipos de erros (depende do programa). Uma versão modificada do que eu já havia mostrado:


rm *.aux &> /dev/null
[[ $? -eq 0 ]] && echo "Tudo removido com sucesso" || echo "Um erro ocorreu, saida do rm=$?"

sigur

Citação de: irtigor online 08 de Junho de 2012, 14:32
A variável $? guarda o ultimo sinal. "0" significa que o programa rodou certo, os outros números indicam os vários tipos de erros (depende do programa). Uma versão modificada do que eu já havia mostrado:


rm *.aux [b]&>[/b] /dev/null
[[ $? -eq 0 ]] && echo "Tudo removido com sucesso" || echo "Um erro ocorreu, saida do rm=$?"


é para ser & ou é 2, como nos outros casos? Vou testar. Não sei se os erros do pdflatex são como os dos comandos do bash. Preciso dar uma saída, mas assim que voltar, eu testo.
Valeu mesmo hein.

irtigor

Tanto faz, eu coloquei "&" pra redirecionar tanto o stdout quanto o stderr (com "2" só redireciona o stderr).

sigur

Olá. Não está fácil de arrumar. Forcei um erro no .tex e ao compilar direto pelo terminal, obtive
pdflatex -halt-on-error caderno.tex
! Missing $ inserted.
<inserted text>
                $
l.358 x^
        2
!  ==> Fatal error occurred, no output PDF file produced!
Transcript written on caderno.log.


Pois bem, tentei redirecionar o erro para um arquivo com
pdflatex -halt-on-error caderno.tex 2> bla
mas o arquivo bla ficou vazio, ou seja, acho que a variável $? que você falou não é usada pelo pdflatex.

Talvez exista algum comando que pause o script caso ocorra algum erro?

Obrigado.

irtigor

#25
Todos os programas fornecem retorno, o que pode acontecer é dele não ser certo (por ex. sempre voltar 0, mesmo com erro). Teste

pdflatex -halt-on-error arquivo_com_erro.tex
echo $?
pdflatex -halt-on-error arquivo_sem_erro.tex
echo $?


Se o retorno for correto, é só criar uma estrutura de desvio (um if).

----
Vale frisar que a variável $? guarda o retorno do ultimo programa executado.

sigur

#26
Que interessante!

Com erro, voltou 1.
Sem erro, voltou 0.

Vou fazer mais testes. Valeu.

Opa. Perfeito. Veja como ficou a parte pra compilar:
pdflatex -halt-on-error caderno.tex 1> /dev/null
[[ $? -eq 1 ]] && echo "| Erro no pdflatex. Verifique os arquivos TeX." && exit
pdflatex -halt-on-error caderno.tex 1> /dev/null
echo "| arquivo caderno.pdf criado"


Se der erro, avisa na tela e para. Caso não tenha erro, compila mais uma vez.
Muito bom. Agora posso descansar.
Bom fim de semana irtigor.

sigur

Prezado colega irtigor, aqui estou mais uma vez para tentar melhorar meu script.

Pois bem, meus arquivos são criados baseados nos arquivos .tex de uma pasta. Esses arquivos não estão nomeados com os nomes dos usuários, mas sim, com os  e-mails. Portanto, quando usoecho "| criando arquivos novos de índice para importação..."
for file in texfiles/comm*.tex ; do
#grep -E '^.author' $file >> indice-comm.tex
echo -e "\\import{$file}\n" >>  indice-comm.tex
sed -e 's;\.tex;;' -i indice-comm.tex
done
echo "| arquivo indice-comm.tex criado"
o resultado não fica por ordem alfabética baseado nos nomes dos users.

Bem, mas dentro de cada arquivo .tex existe o comando \author{} que contém o nome completo de cada user. Então, minha ideia é tentar recuperar essa informação para usá-la na ordenação.

Veja que acima eu fiz um teste com o grep de modo consegui escrever no indice-comm duas linhas para cada $file:
uma com o \author{} e a outra com o \import{$file}. Só que isso não ajuda, pois como vou pedir pra colocar o indice-comm em ordem alfabética? Sei que tem o comando sort, mas daí ele vai colocar tudo o que for \author na frente, vai deixar o \import pro fim, perdendo a relação entre eles.

Acho que dá pra corrigir se eu conseguir escrever essas duas informações na mesma linha do indice-comm. Mas isso eu não sei fazer. Queria escrever no arquivo algo parecido com:
\author{fulano}\import{arquivo}
\author{outro fulano}\import{seu outro arquivo}
e depois classificar alfabeticamente este arquivo.

Alguma ideia mais formal? Obrigado desde já.

irtigor

#28
Em bash você pode fazer algo assim

i=0
while read linha; do
  (( $i%2 == 0 )) && echo -n "\\$linha" || echo "\\$linha"
  let i=$i+1
done < indice-comm.tex > indice-comm-final.tex


Recebe como entrada (indice-comm.tex)

\author{fulano}
\import{arquivo}
\author{outro fulano}
\import{seu outro arquivo}


Produz (indice-comm-final.tex)

\author{fulano}\import{arquivo}
\author{outro fulano}\import{seu outro arquivo}


O unico problema é que não vai ler linhas sem terminador ('\n'), mas isso só é possível na ultima linha, se ela não aparecer coloque (antes do loop)

echo -n '\n' >> indice-comm.tex


----
A contra barra da variável some, adicionei uma ao echo.

sigur

@irtigor, muito obrigado. Ficou perfeito. Entendi mais ou menos o que os comandos fazem. Como quero deixar tudo sempre no mesmo arquivo e não sei se dá pra fazer o input igual ao output, fiz uma gambiarra. Veja:i=0
while read linha; do
   (( $i%2 == 0 )) && echo -n "\\$linha" || echo "\\$linha"
   let i=$i+1
done < indice-comm.tex > temp.tex
sort temp.tex > indice-comm.tex


Deu certinho. Ficou legal.

Como temos arquivos que chamam indice-comm.tex e indice-talk.tex e indice-poster.tex, acabei fazendo 3 vezes as mesmas coisas, sempre trocando o final dos arquivos em questão.

Pergunta: tem como fazer um laço, algo do tipo: para tipo em {comm,talk,poster} do e daí faço os comandos uma vez só, dentro do laço, usando como fonte os arquivos indice-$tipo.tex?

Mais uma vez, obrigado. Ficou perfeito.