2012-02-01 14 views
9

He aquí un ejemplo del comando que estoy usando:rsync para obtener una lista de nombres de archivo sólo

rsync --list-only --include "*2012*.xml" -exclude "*.xml" serveripaddress::pt/dir/files/ --port=111 > output.txt 

¿Cómo puedo obtener una lista de sólo los nombres de archivo sin la información extra, como permisos, marca de tiempo, ¿etc.?

Editar: ¿Y es posible dar salida a cada nombre de archivo en una nueva línea?

+0

Este es un buen ejemplo de lo que está mal con (correcciones y qué PowerShell) * conchas nix populares . –

+0

Otra redacción potencial de preguntas: ¿cómo se filtra 'find' usando' rsync' include y exclude syntax? –

Respuesta

2

Esperando que la pregunta se traslade al sitio apropiado, responderé aquí sin embargo.

Se podría añadir una tubería con awk:

rsync ... | awk '{ $1=$2=$3=$4=""; print substr($0,5); }' >output.txt 

Esto elimina toda la información no deseada mediante la salida de todo, desde el campo quinto, pero sólo funciona si ninguno de los primeros cuatro campos en el formato de salida se pone un adicional espacios en blanco en algún lugar (lo cual es poco probable).

Esta solución awk no funcionará si hay nombres de archivo que comiencen con espacios en blanco.

Una forma aún más robusta de resolver podría ser un programa bastante complejo que también hace suposiciones.

funciona de esta manera: Para cada línea,

  • Corte los primeros 10 bytes. Verifique que vayan seguidos de una cantidad de espacios. Cortarlos también.
  • Corta todos los dígitos siguientes. Verifique que estén seguidos por un espacio. Corta eso también.
  • Corta los siguientes 19 bytes. Verifique que contengan una fecha y una marca de tiempo en el formato apropiado. (No sé por qué los componentes de la fecha están separados con / en lugar de - - no es compatible con ISO 8601.)
  • Compruebe que ahora haya un espacio más. Corta eso también. Deje intactos los siguientes espacios en blanco, ya que pertenecen al nombre del archivo.
  • Si la prueba ha pasado todas estas verificaciones, es probable que el resto de esa línea contenga el nombre del archivo.

Se vuelve aún peor: para casos de esquina muy esotéricos, hay aún más cosas a tener en cuenta: Los nombres de archivo se puede escapar. Ciertos bytes no imprimibles son reemplazados por una secuencia de escape (#ooo con ooo siendo su código octal), un proceso que debe revertirse.

Por lo tanto, ni awk ni un simple script sed harán aquí si queremos hacerlo correctamente.

En cambio, la siguiente secuencia de comandos de Python se puede utilizar:

def rsync_list(fileobj): 
    import re 
    # Regex to identify a line 
    line_re = re.compile(r'.{10} +\d+ ..../../.. ..:..:.. (.*)\n') 
    # Regex for escaping 
    quoted_re = re.compile(r'\\#(\d\d\d)') 
    for line in fileobj: 
     match = line_re.match(line) 
     assert match, repr(line) # error if not found... 
     quoted_fname = match.group(1) # the filename part ... 
     # ... must be unquoted: 
     fname = quoted_re.sub(# Substitute the matching part... 
      lambda m: chr(int(m.group(1), 8)), # ... with the result of this function ... 
      quoted_fname)      # ... while looking at this string. 
     yield fname 

if __name__ == '__main__': 
    import sys 
    for fname in rsync_list(sys.stdin): 
     #import os 
     #print repr(fname), os.access(fname, os.F_OK) 
     #print repr(fname) 
     sys.stdout.write(fname + '\0') 

Esto da salida a la lista de nombres de archivos separados por caracteres NUL, de forma similar a la forma en find -print0 y muchas otras herramientas de trabajo de modo que incluso un nombre de archivo que contiene un carácter de nueva línea (¡que es válido!) se retiene correctamente:

rsync . | python rsf.py | xan -0 stat -c '%i' 

muestra correctamente el número de inodo de cada archivo dado.

Ciertamente, me puedo haber perdido una u otra caja de esquina que no pensé, pero creo que la secuencia de comandos maneja correctamente la mayoría de los casos (probé con todos los 255 nombres de un byte imaginables, así como una nombre de archivo comenzando con un espacio).

+2

bien awk es probablemente la mejor opción para esto, ya que awk entiende que un último operador de campo 'rsync ... | awk '{print $ NF}' ' –

+0

Nunca deberían usarse soluciones oscuras y frágiles como esta. –

+0

@rbtux Buena suerte con un nombre de archivo como 'My favorite song.mp3'. – glglgl

0

rsync ... | sed -E 's|^([^\s]+\s+){4}||'

7

Después de años de trabajo, aquí está mi solución a este antiguo problema:

DIR=`mktemp -d /tmp/rsync.XXXXXX` 
rsync -nr --out-format='%n' serveripaddress::pt/dir/files/ $DIR > output.txt 
rmdir $DIR 
+2

Además, esto puede funcionar, pero no estoy seguro si esto está documentado: 'rsync -nr --out-format = '% n' serveripaddress :: pt/dir/files// dev/false> output.txt' y no, '/ dev/null' no funcionará –

Cuestiones relacionadas