como dividir arquivos e linhas

4

Eu tenho um arquivo de texto como:

1_01                  { ; quite good spirals 


reset=2000 type=mandel passes=1
  corners=-0.6014129278/-0.5990935452/0.427747516/0.429487053
  params=0/0 float=y maxiter=1000 inside=0 outside=15
  distest=1/10/320/200 
  }

1_02                  { ; stringy one, with dist estimator
  reset=2000 type=mandel passes=1
  corners=-1.9228429644992/-1.9228427944992/-6.3749991620026e-008/6.375000\
  8379971e-008 params=0/0 float=y maxiter=1000 inside=0 outside=15
  distest=1/20/320/200
  }

1_03                  { ; OK, bit dull, not zoomed in far 
  reset=2000 type=mandel passes=1
  corners=0.3734922373/0.3820837907/-0.243292645/-0.23684898
  params=0/0 float=y maxiter=1000 inside=0 outside=15
  distest=1/10/320/200
  }

1_04                  { ; a mess, needs dist est
  reset=2000 type=mandel passes=1
  corners=-1.862224008886682/-1.86222400040936/-3.214020831358832e-009/3.1\
  43970347410528e-009 params=0/0 float=y maxiter=1000 inside=0
  outside=15 distest=1/10/320/200 
  }

e gostaria de dividi-lo em arquivos e linhas como:

1_01 { ; quite good spirals
reset=2000
type=mandel
passes=1
corners=-0.6014129278/-0.5990935452/0.427747516/0.429487053
params=0/0
float=y
maxiter=1000
inside=0
outside=15
distest=1/10/320/200
}

Agora eu fiz um script bash:

#!/usr/bin/env bash
# chmod +x s.sh
# ./s.sh
for f in *.txt; 
do  
 echo " found "$f " file ";
 #split -l 7 $f; 
 awk '/{/{n++}{print > n".p" }' $f
 echo $f "- split when { is found  and add p extension " ;
 rm $f;
 echo " input file " $f " is removed " ;
done

for f in *.p;   
do
 echo " in "$f " file replace space with newline and add par extension"
 # tr '{}' '()' < infile > outfile
 tr ' ' '\n' < $f >$f"ar"
 rm $f;
done

for f in *.par;     
do
 echo "remove blank= empty lines"
 sed -i '/^$/d' $f
done

Funciona, mas posso fazer melhor?

    
por Adam 26.12.2014 / 19:47

4 respostas

3

ATUALIZADO: simplificado e testado em gawk (v.3.1.8) e mawk (v. 1.3.3)

Este script do awk deve fazer o que você parece estar pedindo; ele pode funcionar em outras implementações do awk que suportam campos de expressões regulares e separadores de registros:

#!/usr/bin/awk -f

BEGIN {
  RS="}\n\n?"
  ORS="}\n"
  FS="\n"
  OFS="\n"
}

{
  # compress whitespace in first field
  gsub(/[ \t\n]+/," ",$1)

  # split remaining fields on whitespace
  for (i=2;i<=NF;i++) {
      gsub(/[ \t\n]+/,"\n",$i)
  }

  # remove double-newlines resulting from trailing whitespace
  gsub("\n\n+","\n",$0)

  print > NR".par"
}

Teste com sua entrada como file.txt :

$ ./split.awk file.txt

então

$ cat 1.par
1_01 { ; quite good spirals 
reset=2000
type=mandel
passes=1
corners=-0.6014129278/-0.5990935452/0.427747516/0.429487053
params=0/0
float=y
maxiter=1000
inside=0
outside=15
distest=1/10/320/200
}

e

$ cat 3.par
1_03 { ; OK, bit dull, not zoomed in far 
reset=2000
type=mandel
passes=1
corners=0.3734922373/0.3820837907/-0.243292645/-0.23684898
params=0/0
float=y
maxiter=1000
inside=0
outside=15
distest=1/10/320/200
}
    
por 26.12.2014 / 21:34
2

Eu coloquei seus dados de exemplo em ./file como:

cat >file <<\IN
# all of your example
IN 

Então fiz o seguinte:

sed -n 's|\([^ ]*\) *{.*|/ {/,/}/w file..par|p' file | 
sed -e 's/  */ /g;s/^ //;s/ $//;/./!d;/{/!y/ /\n/' -f - file

Isso usa um processo sed para remover os dados no arquivo e editá-los em um script sed viável para um segundo processo sed .

O script que acaba sendo executado parece ...

/1_01 {/,/}/w file.1_01.par
/1_02 {/,/}/w file.1_02.par
/1_03 {/,/}/w file.1_03.par
/1_04 {/,/}/w file.1_04.par

... mas só é executado depois do segundo sed para cada linha no arquivo ...

... -e 's/  */ /g;s/^ //;s/ $//;/./!d;/{/!y/ /\n/' ...

... que primeiro espreme qualquer seqüência de espaços em um único espaço, remove um espaço à esquerda ou à direita se eles permanecerem, exclui linhas vazias inteiramente da saída e, por último, converte todos os espaços em um caractere \n ewline para cada linha que não corresponde a { .

Portanto, para cada número de linha que corresponda a (section heading) *{.* , o segundo sed w o rita e todas as linhas subseqüentes até e incluindo o próximo } na entrada para file.(section heading) , enquanto o infil original não é afetado .

Depois de executar o que fiz ...

cat <./file.1_01.par

... e ...

1_01 { ; quite good spirals 
reset=2000
type=mandel
passes=1
corners=-0.6014129278/-0.5990935452/0.427747516/0.429487053
params=0/0
float=y
maxiter=1000
inside=0
outside=15
distest=1/10/320/200
}

Para executar, basta copiar / colar essas duas linhas sed ... em seu terminal e substituir o nome arquivo pelo que for apropriado.

Eu também participei do link em sua pergunta ...

sed -n 's|.\([^ ]*\) {.*|/ {/,/^}$/w .par|p' <<-IN |\ 
sed -e 's/.//;/{/!y/ /\n/' -f - all.par
    $(curl -s 'http://www.calresco.org/pic3/calres3.par' |
    tr -s '\r\n ' '\n  ' |tee all.par)
IN

Isso dividiu todas as funções .par em seus próprios arquivos - e manipulou as terminações de linha do DOS:

ls -C
a46.par       bugeyed.par  flocks.par    iconw2b.par   manchaos.par  swirl5.par
aciddrop.par  burr.par     galaxy.par    juliland.par  mandelzm.par  trific.par
all.par       complex.par  highrise.par  lace.par      redgiant.par
angfish.par   eyeeye.par   iconvolc.par  lavaflow.par  scythe.par

Eles são todos nomeados para o nome da função.

cat galaxy.par

galaxy {;Chris Lucas
reset=1950
type=julia
center-mag=+0.03023290053994965/+0.26628255550711930/42.69126/1/67.5
params=-0.1582146627566066/0.6550294654497986
float=y
maxiter=30000
colors=000000GFF<28>x11z00z10<29>zx0zz0zz1<29>zzxzzzzzz<61>zV1zU0zU0zT0<\
28>z10z00z00y00<30>c00b11a11'22_22<25>FFF
}
    
por 26.12.2014 / 21:22
1

Tente csplit: inputfile == frac.txt , arquivos de saída == frac[nn] (onde nn > 00, porque o arquivo # 00 está vazio)

 csplit -f frac frac.txt /^1/ {*}
    
por 26.12.2014 / 20:21
1

A formatação de linha só pode ser feita por sed sozinho:

sed -i 's/^\s*\|\s*$//g ; s/\s\s*/ /g ; /[{}]/!s/ /\n/g ; /^\s*$/d' *.txt
    
por 26.12.2014 / 20:36