2009-10-20 13 views
5

Tengo un archivo que tiene una línea en el archivo de la siguiente manera:Mover a seguir otra línea en un archivo

check=('78905905f5a4ed82160c327f3fd34cba') 

me gustaría ser capaz de mover esta línea para seguir una línea que se ve así:

files=('somefile.txt') 

La matriz aunque a veces que puede abarcar varias líneas, por ejemplo:

files=('somefile.txt' 
     'file2.png' 
     'another.txt' 
     'andanother...') 

text 
in between 

check=('78905905f5a4ed82160c327f3fd34cba' 
     '5277a9164001a4276837b59dade26af2' 
     '3f8b60b6fbb993c18442b62ea661aa6b') 

La matriz/línea alway s termina en a) y ningún texto intermedio contendrá un paréntesis cerrado.

me dieron algunos consejos que awk puede hacer esto:

awk '/files/{ 
    f=0 
    print $0 
    for(i=1;i<=d;i++){ print a[i] } 
    g=0 
    delete a # remove array after found 
    next 
} 
/check/{ f=1; g=1 } 
f{ a[++d]=$0 } 
!g' file 

Esto sólo tendrá una duración de una línea sin embargo. Me dijeron que expandir la búsqueda:

awk '/source/ && /\)$/{ 
    f=0 
    print $0 
    for(i=1;i<=d;i++){ print a[i] } 
    g=0 
    delete a # remove array after found 
    next 
} 
/md5sum/ && /\)$/{ f=1; g=1 } 
f{ a[++d]=$0 } 
!g' 

Acabo de aprender awk así que agradecería ayuda con esto. O si hay otra herramienta que puede hacer esto, me gustaría saberlo. Alguien me dijo que 'ed' este tipo de capacidades.

+0

Aha, necesidad para mover las líneas hacia arriba y hacia abajo, ¿verdad? He revisado la respuesta a continuación ... – DigitalRoss

Respuesta

2

para responder a su última pregunta, sí, awk es la herramienta de Unix típico para esto, otros candidatos son el increíblemente poderoso Perl, Python, o mi favorito .. .. Ruby. Una ventaja de awk es que siempre está ahí; es parte del sistema base. Otra forma de resolver este tipo de problema es con un script de editor que controla ed(1) o ex(1).

Ok, nuevo programa para la pregunta revisada. Este programa moverá las líneas de "control" hacia arriba o hacia abajo según sea necesario para que sigan las líneas de "archivos".

BEGIN { 
    checkAt = 0 
    filesAt = 0 
    scanning = 0 
} 

/check=\(/ { 
    checkAt = NR 
    scanning = 1 
} 

/files=\(/ { 
    filesAt = NR 
    scanning = 1 
} 

/)$/ { 
    if (scanning) { 
    if (checkAt > filesAt) { 
     checkEnd = NR 
    } else { 
     filesEnd = NR 
    } 
    scanning = 0 
    } 
} 

{ 
    lines[NR] = $0 
} 

END { 
    for (i = 1; i <= NR; ++i) { 
    if (checkAt <= i && i <= checkEnd) { 
     continue 
    } 
    print lines[i] 
    if (i == filesEnd) { 
     for (j = checkAt; j <= checkEnd; ++j) { 
     print lines[j] 
     } 
    } 
    } 
} 
+0

Oye, eso es genial, sin embargo, el paréntesis de cierre está siendo truncado. es decir, check = (.... El ejemplo que probé en la matriz de archivos estaba al final del archivo. ¿Eso hizo una diferencia? Además, ¿podría funcionar si la matriz de archivos está antes de la matriz de verificación?) Me parece diferente en algunos archivos. –

+0

Bien, si agrega esta línea al final de 'mover.awk', tratará el caso donde lo último en el archivo es una línea de verificación():' FIN {para (v en guardado) {impresión guardada [ v]}} '* sin embargo * No puedo reproducir su) informe de error de truncamiento. ¿Pueden enviar un caso de prueba a http://pastie.org (utilizar el tipo de archivo "texto sin formato")? – DigitalRoss

+0

He puesto una versión actualizada de la secuencia de comandos en http://pastie.org/662905 Esta versión trata sobre el orden invertido superando la última comprobación si ve una nueva, y sacando la que queda en EOF. Pero aún necesito un caso de prueba porque no puedo reproducir tu error. – DigitalRoss

0

Así es como hacerlo con SED:

 
sed -e /^check=(/,/)/{H;d} -e /)/{G;s/\n//} < filename 

Esto supone que no hay paréntesis de después los "archivos = ..." Si hay, entonces tendrá más precisión:

 
sed -e /^check=(/,/)/{H;d} -e /^files=(/,/)/{/)/{G;s/\n//}} < filename 

EDIT:
Trabajando en bash? Muy bien, intente esto:

 
sed -e /^check=(/,/)/H -e /^check=(/,/)/d -e '/)/G;s/\n//' < filename 

Esto parece funcionar, pero no es claro por qué esta variante y no los otros pocos obvias. Este baile de los personajes especiales siempre es un problema con expresiones regulares.

+1

Wow tratando de hacer con sed, un hombre valiente: P. Sí, intenté esto con sed, pero entendiendo los registros aún no he llegado al límite. Desde tu comando, parece que bash está tratando de interpretar el paréntesis. Intenté escapar de ellos pero estoy obteniendo: sed: -e expresión # 1, char 0: inigualable '{' bash: d}: comando no encontrado bash: s/n //}}: No existe ningún archivo o directorio –

+0

Still sin suerte. Usando gnu-sed 4.2.1 aquí. bash: error de sintaxis cerca del token inesperado '( –

+0

* suspiro * Si le interesa, podríamos hacer algunos experimentos y ponerlo en funcionamiento, pero como ya tiene una solución de trabajo en awk, sería simplemente una experiencia al aprender sed. – Beta

0

Intenté hacer esto con Awk, pero parecía que en realidad no obtendría nada inteligente, sería la misma lógica, pero con un poco de dolor Awk, así que lo hice en Perl :)

#!/usr/bin/perl 

open(IN, $ARGV[0]) || die("Could not open file: " . $ARGV[0]); 

my $buffer=""; 

foreach $line (<IN>) { 
     if ($line =~ /^check=/) { 
       $flag = 1; 
       $buffer .= $line; 
     } elsif ($flag == 1 && $line =~/\)/) { 
       $flag = 0; 
       $buffer .= $line; 
     } elsif ($flag == 1) { 
       $buffer .= $line; 
     } elsif ($flag == 0 && $line =~ /^files=/) { 
       $flag = 2; 
       print $line; 
     } elsif ($flag == 2 && $line =~ /\)/) { 
       $flag = 0; 
       print $line; 
       if (length($buffer) > 0) { 
         print $buffer; 
         $buffer = ""; 
       } 
     } else { 
       print $line; 
     } 

} 

Y la salida :)

Chill:~ rus$ cat test check=('78905905f5a4ed82160c327f3fd34cba' 
     '5277a9164001a4276837b59dade26af2' 
     '3f8b60b6fbb993c18442b62ea661aa6b') 

text in between 

files=('somefile.txt' 
     'file2.png' 
     'another.txt' 
     'andanother...') 

asdasdasd 

check=('78905905f5a4ed82160c327f3fd34cba' 
     '5277a9164001a4276837b59dade26af2' 
     '3f8b60b6fbb993c18442b62ea661aa6b') 

text in between 

files=('somefile.txt' 
     'file2.png' 
     'another.txt' 
     'andanother...') 

asdsd 

check=('78905905f5a4ed82160c327f3fd34cba' 
     '5277a9164001a4276837b59dade26af2' 
     '3f8b60b6fbb993c18442b62ea661aa6b') 

text in between 

files=('somefile.txt' 
     'file2.png' 
     'another.txt' 
     'andanother...') 

Chill:~ rus$ ./t.pl test 

text in between 

files=('somefile.txt' 
     'file2.png' 
     'another.txt' 
     'andanother...') check=('78905905f5a4ed82160c327f3fd34cba' 
     '5277a9164001a4276837b59dade26af2' 
     '3f8b60b6fbb993c18442b62ea661aa6b') 

asdasdasd 


text in between 

files=('somefile.txt' 
     'file2.png' 
     'another.txt' 
     'andanother...') check=('78905905f5a4ed82160c327f3fd34cba' 
     '5277a9164001a4276837b59dade26af2' 
     '3f8b60b6fbb993c18442b62ea661aa6b') 

asdsd 


text in between 

files=('somefile.txt' 
     'file2.png' 
     'another.txt' 
     'andanother...') check=('78905905f5a4ed82160c327f3fd34cba' 
     '5277a9164001a4276837b59dade26af2' 
     '3f8b60b6fbb993c18442b62ea661aa6b') 

ta da?!: D

+0

urgh , la pasta de salida está estropeada, pero créanme, funciona. Estoy celoso de las soluciones awk y sed :) – RusHughes

+0

nah, esto es bueno. Aunque no funciona para mí. La matriz de archivos se borra y la matriz de archivos aún existe. Obtuve {y() personajes entre las dos matrices, ¿esto hace la diferencia? –

+0

¡Agregué cargas de {()} caracteres a mis datos de prueba y todavía funcionó bien! ¿Tiene un ejemplo de los datos de prueba que puedo probar? – RusHughes

0

@todd, parece que te he dejado en la estacada después de proporcionarte la solución awk ¿no? ? :). aquí hay otro método, esta vez no usa el método de banderas. hay algunos cabos sueltos (sugerencia: compruebe los patrones p, qy la salida de nuevo) que le dejo a usted ordenar.

gawk 'BEGIN{ 
    RS="check=[(]" 
    q="files=(.*\047)" # pattern to replace files= part 
    p=".*(files=(.*\047)).*" # to get the whole files= part to variable 
} 
NR>1{ 
    b=gensub(p, "\\1","g",$0) # get the files=part to var b 
    printf "%s\n\n",b  
    printf "check=(" 
    gsub(q,"",$0) 
    print $0 
}' file 

NB: funciones predefinidas gensub es específico para curiosear lo que si tiene gawk, entonces eso está bien

salida

$ more file 
check=('5277a9164001a4276837b59dade26af2' 
     '5277a9164001a4276837b59dade26af2' 
     '3f8b60b6fbb993c18442b62ea661aa6b') 

text in between one 

files=('somefile1.txt' 
     'file1.png'  
     'another1.txt' 
     'andanother1...') 

asdasdasd blah blah 

check=('78905905f5a4ed82160c327f3fd34cba' 
     '5277a9164001a4276837b59dade26af2' 
     '3f8b60b6fbb993c18442b62ea661aa6b') 

text in between two 

files=('somefile2.txt' 
     'file2.png'  
     'another2.txt' 
     'andanother2...') 

asdsd blaasdf aslasdfaslj aslfjsldfsa 123e12 

check=('78905905fblah blah5a4ed82160c327f3fd34cba' 
     '5277a9164001a4276837b59dade26af2'   
     '3f8b60b6fbb993c18442b62ea661aa6b')   

text in between 

files=('somefile3.txt' 
     'file3.png'  
     'another3.txt' 
     'andanother3...') 

$ ./shell.sh 
files=('somefile1.txt'    
     'file1.png'     
     'another1.txt'    
     'andanother1...'    

check=('5277a9164001a4276837b59dade26af2' 
     '5277a9164001a4276837b59dade26af2' 
     '3f8b60b6fbb993c18442b62ea661aa6b') 

text in between one 

) 

asdasdasd blah blah 


files=('somefile2.txt' 
     'file2.png' 
     'another2.txt' 
     'andanother2...' 

check=('78905905f5a4ed82160c327f3fd34cba' 
     '5277a9164001a4276837b59dade26af2' 
     '3f8b60b6fbb993c18442b62ea661aa6b') 

text in between two 

) 

asdsd blaasdf aslasdfaslj aslfjsldfsa 123e12 


files=('somefile3.txt' 
     'file3.png' 
     'another3.txt' 
     'andanother3...' 

check=('78905905fblah blah5a4ed82160c327f3fd34cba' 
     '5277a9164001a4276837b59dade26af2' 
     '3f8b60b6fbb993c18442b62ea661aa6b') 

text in between 

) 
+0

Gracias fantasma. He estado abarrotando en awk los últimos días y aún no lo entiendo. Aún estoy aprendiendo sed Supongo que soy del tipo que le gusta aprender sobre algo y aprenderlo bien antes de continuar: D. Apreciar la ayuda, muy apreciada. –

0

Esto podría funcionar para usted:

sed ':a;$!N;/^files=.*\ncheck=/{/.*)$/!ba;s/\([^)]*)\)\(.*\)\(\ncheck=.*\)/\1\3\2/p;d};/^files=.*/ba;P;D' file 
Cuestiones relacionadas