Mesclando arquivos de texto e adicionando separador

1

Eu quero adicionar um separador como este "==============" e uma nova linha em branco

Eu tentei fazer isso, mas falhei e causa alto uso da CPU. Quero dizer, a cpu torna-se rotativa ery rápido e barulhento quando eu executar o script

Isso precisa ser em torno de 100.000 arquivos de texto.

este é o código que eu uso

#!/bin/bash
for F in *.txt ; do
    type "$F"
    echo .
    echo ========
    echo . 
done >> Combined.txt;

por favor, conselhos

    
por Jeff Schaller 07.10.2018 / 22:37

4 respostas

1

Se você for fazer isso para milhares de arquivos, você pode evitar a execução de vários comandos por arquivo. Com o GNU awk :

printf '%s
#! /bin/ksh93
firstpass=true
for file in *.txt; do
  "$firstpass" || print '\n===========\n'
  firstpass=false
  command /opt/ast/bin/cat < "$file"
done > combined.out
' ./*.txt | xargs -r0 gawk ' BEGINFILE {if (NR) print "\n==========\n"};1' > combined.out

Não dê uma extensão .txt ao arquivo de saída se você for colocá-lo no mesmo diretório, ou ele será selecionado como um arquivo de entrada e causar um loop infinito (provavelmente o seu problema no primeiro lugar).

Ou use um shell no qual cat é criado como ksh93 :

printf '%s
#! /bin/ksh93
firstpass=true
for file in *.txt; do
  "$firstpass" || print '\n===========\n'
  firstpass=false
  command /opt/ast/bin/cat < "$file"
done > combined.out
' ./*.txt | xargs -r0 gawk ' BEGINFILE {if (NR) print "\n==========\n"};1' > combined.out

Todos esses comandos no loop são internos, portanto, executá-los não envolve a criação de novos processos nem o carregamento de executáveis externos, o que tornaria o desempenho tolerável.

    
por 07.10.2018 / 23:55
0

Eu simplificaria seus comandos da seguinte forma:

  #!/bin/bash
  for file in *.txt; do
  cat $file >> Combined.txt
  printf '\n\n=========\n\n' >> Combined.txt
  done
    
por 07.10.2018 / 23:07
0

Usando FNR e NR em awk

#!/bin/bash

outfile="$( mktemp combined.txt.XXXXXX )"

echo "Output file: ${outfile}"

awk 'FNR==1 && NR>1 { printf("\n%s\n\n","========") } 1' *.txt > "${outfile}"

echo "Finished."

Uma descrição linha a linha:

outfile="$( mktemp combined.txt.XXXXXX )"

Use mktemp para criar um novo arquivo vazio com um nome exclusivo (por exemplo, combined.txt.HDpgMn ). Você pode usar mais X caracteres para um sufixo aleatório mais longo. Coloque o comando em "$( ... )" para armazenar o nome do novo arquivo na variável outfile .

echo "Saving to file: ${outfile}"

Imprima o nome do arquivo de saída. (Quando o script terminar, você pode querer renomear o arquivo de saída para remover a seqüência de caracteres aleatórios após o .txt .)

awk 'FNR==1 && NR>1 { printf("\n%s\n\n","========") } 1' *.txt > "${outfile}"

Imprimir ...

  • uma linha em branco,
  • uma pequena linha de caracteres "=",
  • e outra linha em branco

... no início de cada arquivo de entrada, exceto pelo primeiro arquivo de entrada. FNR conta os números de linha do arquivo de entrada, redefinindo no início de cada arquivo. NR conta os números de linha e não redefine.

Na instrução awk , o 1 imediatamente antes da aspa simples do fechamento é avaliado como TRUE para cada linha e executa a ação padrão de imprimir essa linha. (Em outras palavras, awk '1' funciona como cat .)

echo "Finished."

Informe o usuário quando o script estiver pronto. (Não é estritamente necessário, pois você verá o prompt de comando de qualquer maneira, mas não faz mal.)

    
por 08.10.2018 / 01:02
0

Por que não simplesmente

printf "\n\n=====\n\n" > XTMP
cat $(printf "%s XTMP " *.txt) > combined.tmp

Coloque o separador em um arquivo temporário e use o recurso printf para repetir a string de formatação para cada argumento encontrado, portanto, o comando cat será parecido com

cat 1.txt XTMP 2.txt XTMP ... n.txt XTMP

Você pode encontrar limites do sistema (por exemplo, LINE_MAX), embora ...

    
por 11.10.2018 / 00:13