Fórum Ubuntu Linux - PT
Suporte Técnico => Programação e Scripts => Tópico iniciado por: sigur em 30 de Maio de 2012, 16:37
-
Pessoal, tentei adaptar um modelo de uso do sed, que encontrei aqui, para comentar uma linha de um arquivo, mas não estou conseguindo.
Pois bem, quero comentar todas as linhas do meu arquivo TeX que começam com \usepackage.
O problema é que não consigo fazer a troca, ou melhor, inserir o símbolo % na frente destas linhas, pois eu acho que a barra e o % precisar ser passados de modo diferente.
Tentei
sed /\usepackage/%\usepackage/ 1.tex > 2.tex
mas o erro foi sed: -e expressão #1, caractere 12: comando desconhecido: `%'
alguma ajuda?
Em resumo, preciso inserir % em vários arquivos TeX nas linhas que começam com \usepackage
Obrigado.
-
sed 's;^\\usepackage;%\\usepackage;' 1.tex
Substitui linhas que começam com \usepackage por %\usepackage. Você pode usar a opção "-i/--in-place" pra substituir diretamente.
-
sed 's;^\\usepackage;%\\usepackage;' 1.tex
Substitui linhas que começam com \usepackage por %\usepackage. Você pode usar a opção "-i/--in-place" pra substituir diretamente.
perfeito!!
muito obrigado. O que quer dizer com 'substituir diretamente'?
Só mais uma pergunta: se eu quiser fazer mais de uma substituição no mesmo arquivo, por exemplo, comentar também as linhas que começam com \title, posso fazer como? tentei fazer
sed 's;^\\usepackage;%\\usepackage;' 's;^\\title;%\\title;' 1.tex
mas não deu.
Tentei sed 's;^\\usepackage;%\\usepackage;' 1.tex | sed 's;^\\title;%\\title;' > 2.tex
mas não deu
Será que terei que criar um .sh e inserir um monte de linhas, uma para cada comando sed trocando as coisas?
Obrigado mais uma vez. Já ajudou bem.
-
sed -e 's;^\\usepackage;%\\usepackage;' -e 's;^\\title;%\\title;' 1.tex
Com um "-i" o arquivo 1.tex seria modificado, no lugar do resultado aparecer na saída padrão.
-
sed -e 's;^\\usepackage;%\\usepackage;' -e 's;^\\title;%\\title;' 1.tex
Com um "-i" o arquivo 1.tex seria modificado, no lugar do resultado aparecer na saída padrão.
ah, entendi. então ele altera e escreve no próprio arquivo? é como se fosse mexer em 1.tex e mandar a saída pro próprio 1.tex?
eu havia tentado colocar 1.tex > 1.tex no fim do comando, mas o resultado ficou um arquivo em branco.
daí eu fiz uma gambiarra. Veja o que eu fiz:
cat texfiles/comm*.tex > tudo.tex
sed 's;^\\documentclass;%\\documentclass;' tudo.tex > temp.tex
mv temp.tex tudo.tex
sed 's;^\\usepackage;%\\usepackage;' tudo.tex > temp.tex
mv temp.tex tudo.tex
sed 's;^\\begin{document};%\\begin{document};' tudo.tex > temp.tex
mv temp.tex tudo.tex
sed 's;^\\end{document};%\\end{document};' tudo.tex > temp.tex
mv temp.tex comm.tex
rm tudo.tex
Deu certo, mas não ficou nem um pouco legal.
Agora vou tentar sua dia.
Mais uma vez, obrigado.
-
http://wiki.bash-hackers.org/howto/redirection_tutorial#why_sed_sfoobarfile_file_doesn_t_work
-
http://wiki.bash-hackers.org/howto/redirection_tutorial#why_sed_sfoobarfile_file_doesn_t_work
muito bom. consegui usar suas dicas e colocar um monte de subs. no mesmo comando. agora é só executar o .sh e partir pro abraço.
Valeu hein.
-
Opa, eu novamente.
Não estou tendo tanto sucesso pra compilar tudo de uma vez. Mas isso é detalhe. Portanto, estou querendo fazer o seguinte:
para cada arquivo .tex dentro de uma pasta, queria copiar as linhas que começam com \title e com \author, copia-las nesta ordem, para um outro arquivo.
Tentei usar o cat 1.tex | grep \title mas o problema é que ele retorna também as linhas que começam com \maketitle. Não sei porque, mas ele não segue fielmente a palavra.
A outra dificuldade é fazer buscar, para um mesmo arquivo, as duas linhas de uma vez.
Será que dá pra fazer um .sh?
Valeu.
-
A contra barra é um carácter de escape (http://wiki.bash-hackers.org/syntax/quoting#quotes_and_escaping). Use
grep -E '(^\\title|^\\author)' arquivo.tex
-
A contra barra é um carácter de escape (http://wiki.bash-hackers.org/syntax/quoting#quotes_and_escaping). Use
grep -E '(^\\title|^\\author)' arquivo.tex
opa, legal. Obrigado.
Veja como está ficando:
for file in texfiles/*.tex; do
sed -e 's;\\maketitle;\\maketitle\\thispagestyle{empty}\\pagestyle{empty};' -i $file
done
rm indice-comm.tex # dá erro se o file não existe. queria colocar um if
for file in texfiles/comm*.tex ; do
grep -E '^.title|^.author' $file >> indice-comm.tex # trocar pela sua sugestão
echo -e " " >> indice-comm.tex # gambiarra pra pular linha no arquivo
sed -e 's;^\\title;\\titulo;' -e 's;^\\author;\\autor;' -i indice-comm.tex
done
# compilar em pdf os comm*.tex da pasta texfiles
for file in texfiles/comm*.tex; do
pdflatex $file
pdflatex $file
mv comm*.pdf pdffiles/
done
rm *.aux
rm *.log
#rm *.out
# juntar todos os comm*.pdf em um arquivo só
# chamado resumos-comm.pdf
pdftk pdffiles/comm*.pdf cat output resumos-comm.pdf
-
Pessoal, queria fazer um teste para saber se existe algum arquivo no diretório com extensão .log ou .aux. Caso sim, queria redeltar todos eles.
Tentei fazer
if [ -f *.aux ];
then
rm *.aux
rm *.log
else
echo "nao tem nenhum aux"
fi
mas aparece o erro
./lista.sh: linha 9: [: número excessivo de argumentos
Alguma ajuda?
-
"-f" testa se 1 arquivo é normal. Se no diretório tem 1.aux e 2.aux, *.aux vai ser expandido para esses dois, então vai ficar [ -f 1.aux 2.aux ] o que é errado.
Você pode usar um loop ou remover de qualquer forma, redirecionando o stderr pra /dev/null.
-
"-f" testa se 1 arquivo é normal. Se no diretório tem 1.aux e 2.aux, *.aux vai ser expandido para esses dois, então vai ficar [ -f 1.aux 2.aux ] o que é errado.
Você pode usar um loop ou remover de qualquer forma, redirecionando o stderr pra /dev/null.
Hum, entendi o uso do -f.
Quando você diz para usar um loop, seria um for? Mas como saber se existem arquivos .aux na pasta, para que o rm dentro do for não dê erro?
Veja se entendi: essa parte do null seria para mandar a msg de erro pra lá? Lembro de ter lido algo assim. Então, se eu fizer apenas
rm *.aux > /dev/null
sempre dará certo, pois não verei msg de erros na tela? Se tiver erros, isso deixará mais lento a execução?
Valeu por enquanto.
-
for i in *.aux; do
[[ -f "$i" ]] || continue
rm "$i"
done
rm *.aux 2> /dev/null
[[ $? -eq 1 ]] && echo "nao tem nenhum aux"
O segundo deve ser mais rápido porque pega todos os arquivos de uma só vez, enquanto o outro trabalha em série.
-
Opa, legal hein. Valeu pela ajuda.
Só não entendi muito o porque de dois [[.
Mas está ficando show de bola.
Obrigado.
-
É 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.
-
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 "| ###########################"
-
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.
-
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.
-
Olhei o manual, se você usar a opção "-halt-on-error" o que eu falei deve funcionar.
-
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!
-
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=$?"
-
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.
-
Tanto faz, eu coloquei "&" pra redirecionar tanto o stdout quanto o stderr (com "2" só redireciona o stderr).
-
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.
-
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.
-
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.
-
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á.
-
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.
-
@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.
-
Expansão de chaves
for i in indice-{comm,talk,poster}.tex; do
# use o "$i"
done
Três voltas, i assume os valores: indice-comm.tex, indice-talk.tex e indice-poster.tex. Pra pegar só a diferença, vai ter que usar manipulação de string.
----
Não tem como a entrada ser igual a saída, o redirecionamento é criado antes, portanto a arquivo ficaria truncado.
-
Opa. Está quase tudo certo. Percebi que tem algo errado com a paginação do pdf gerado no fim. Por algum motivo, o número de página inserido não corresponde ao número real.
Isso só ocorre se compilo com o script. Usando o pdflatex direto no terminal, tudo funciona. Pensei que fosse algum problema em deletar os aux, mas não sei. Já comentei e continua na mesma.
Fuçando nos arquivos indice-* criados, notei coisas estranhas. Por exemplo, depois de colocar as linhas do \import{} na frente das linhas do \author{}, um deles ficou com \bla{xxx}^M\import{zzzz}
ou seja, aparece um ^M.
Também, alguns arquivos possuem dois comandos \author{} em linhas consecutivas. Daí, o \author subiu só em uma delas e o \import ficou, ao invés de ficar com \author{xxx}\author{www}\import{zzzz}
Estranho! Acho que terei que editar a fonte para tirar essa duplicidade.
não tem como fazer uma busca com o grep e fazer a troca de um comando e logo na frente usar o echo para escrever o nome do arquivo e salvar tudo isso em um file com o uso do > ? Algo do tipogrep 'bla' foo | sed 's/bla/mmm/' [b]E[/b] echo '$file' > file.tex
Qual a diferença entre echo ' ' e echo " " ?
-
http://wiki.bash-hackers.org/syntax/quoting#quotes_and_escaping
Com sed
sed -i '/baz/s/foo/bar/' file.txt
Substitui foo por bar, somente nas linhas com baz.
-
Estou tentando guardar os comandos em duas variáveis, para usar o echo e já colocar uma na frente da outra. Mas se eu digitar tudo no terminal, como abaixo, deu certinho. Porém, usando o .sh não funciona, a saída fica com 3 linhas, mas vazias.
Tudo no terminal:
for file in texfiles/comm1*.tex; do autor=$(grep -E '^.author' $file); arquivo=$(echo -e "\\import{$file}"); echo $autor$arquivo >> indice-comm.tex; done
Bloco do .sh
echo "| criando arquivos novos de índice para importação..."
for file in texfiles/comm*.tex ; do
autor = $( grep -E '^.author' $file ) #| sed -e 's;\\author;\\bla;' ); #>> indice-comm.tex
arquivo = $( echo -e "\\import{$file}" ) #| sed -e 's;\.tex;;' ); #>> indice-comm.tex
echo $autor$arquivo >> indice-comm.tex
done
nesse dá erro:
./criar-caderno.sh: linha 25: autor: comando não encontrado
./criar-caderno.sh: linha 26: arquivo: comando não encontrado
./criar-caderno.sh: linha 25: autor: comando não encontrado
./criar-caderno.sh: linha 26: arquivo: comando não encontrado
./criar-caderno.sh: linha 25: autor: comando não encontrado
./criar-caderno.sh: linha 26: arquivo: comando não encontrado
Não entendo o uso de ponto-vírgula.
Obrigado.
-
for file in texfiles/comm*.tex ; do
autor="$(grep -E '^\\author' "$file")"
echo "$autor\\import{$file}" >> indice-comm.tex
done
Usar um subshell pra um echo não é uma boa ideia.
-----
Uma alteração, no exemplo anterior não usei o -r do read, assim é melhor
i=0
while read -r 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
-
Prezado colega. Muito obrigado pela ajuda e desculpe por fazê-lo trabalhar demais. Conforme fui estudando, percebi que podia fazer mais simples, ou seja, já pude escrever no arquivo uma linha na frente da outra, ou melhor, os dois comandos na mesma linha. Daí, não precisei da gambiarra pra juntar duas linhas.
Pois bem, agora acho que está tudo redondo, consertei o problema da paginação. Só não sei porque motivo algumas linhas do \import não juntaram. Mas tudo bem, pro TeX não tem problema, o importante é usar o sort.
Veja como ficou o bloco
echo "| criando arquivos novos de índice para importação..."
for file in texfiles/comm*.tex ; do
autor="$(grep -E '^\\author' "$file" | sed -e 's;\\author;\\bla;' )"
echo "$autor\\import{$file}" >> temp.tex
sed -e 's;\.tex;;' -i temp.tex
done
sort temp.tex > indice-comm.tex
rm temp.tex 2> /dev/null
echo "| arquivo indice-comm.tex criado"
Troquei o \author por \bla pois não posso ter mais de um no mesmo arquivo tex. Daí, defini o \bla como vazio e pronto.
Obrigado mesmo pela ajuda hein.
Valeu.