2010-12-29 17 views
6

En Perl se utiliza:¿Cuál es el equivalente de Perl (<>) en Python? fileinput no funciona como se esperaba

while (<>) { 
    # process files given as command line arguments 
} 

En Python que encontré:

import fileinput 
for line in fileinput.input(): 
    process(line) 

Pero, ¿qué ocurre cuando el archivo dado en la línea de comandos que no existe?

python test.py test1.txt test2.txt filenotexist1.txt filenotexist2.txt test3.txt como argumento.

Probé varias formas de usar try: except: nextfile, pero no pude hacer que funcione.

Para la línea de comandos anterior, la secuencia de comandos debe ejecutarse para test1-3.txt, pero simplemente vaya al siguiente archivo en silencio cuando NO se encuentre el archivo.

Perl lo hace muy bien. He buscado esto en toda la red, pero no pude encontrar la respuesta a este en ninguna parte.

+0

No sé antes de publicar este paquete. Parece muy útil. – VGE

+0

"pero simplemente ve al siguiente archivo en silencio cuando el archivo NO se encuentra."? De Verdad? ¿Por qué? Si el archivo no existe, ¿por qué no debería romperse todo? –

+1

@ S.Lott: piensa en las utilidades de línea de comandos de unix como grep.Funcionan con argumentos válidos, pero solo dan advertencias en archivos inexistentes, y las advertencias no provocan que el comando completo aborte, aunque hace que el comando salga con un estado de error. Dicho esto, Perl no es "silencioso" en archivos inexistentes, también da advertencias. – runrig

Respuesta

5
import sys 
import os 

for f in sys.argv[1:]: 
    if os.path.exists(f): 
     for line in open(f).readlines(): 
      process(line) 
+0

gracias por esto ... ¿hay alguna otra respuesta con las pulsaciones de teclas más simples ... en Perl .. while (<>) {} << solo se requieren unos pocos caracteres ... cualquier atajo similar con python. – ihightower

+2

@ihightower Sí. Toma mi método, ponlo en un módulo e impórtalo. Todo lo que necesita es 'para la línea en read_lines():'. Python no apunta a operadores oscuros con un mínimo de teclas, por lo que no encontrarás algo tan escueto como '<>' de Perl, pero * podrías * renombrar el método a algo como 'rl()' para obtener 'for l in rl(): 'si es absolutamente necesario. – marcog

+0

Esto no tiene en cuenta los otros posibles errores, como archivo no legible, archivo es un directorio, archivo de texto bloqueado, etc. Estoy realmente de acuerdo con el OP que si 'fileinput' quiere ser útil, debe ofrecer control sobre este aspecto de su operación. – tripleee

3

Algo como esto;

import sys 

for f in sys.argv[1:]: 
    try: 
     data = open(f).readlines() 
     process(data) 
    except IOError: 
     continue 
0

tal vez usted puede jugar con el parámetro para controlar openhook archivo no existente.

3

Volviendo @ respuesta de Brian en un generador, y la captura de IOError en lugar de probar por la existencia que es más Pythonic y luego imprimir una advertencia a stderr en caso de fallo:

import sys 

def read_files(files = None): 
    if not files: 
    files = sys.argv[1:] 
    for file in files: 
    try: 
     for line in open(file): 
     yield line 
    except IOError, e: 
     print >>sys.stderr, 'Warning:', e 

for line in read_files(): 
    print line, 

de salida (el archivo baz no existe) :

$ python read_lines.py foo bar baz 
line 1 of foo 
line 2 of foo 
line 1 of bar 
line 2 of bar 
Warning: [Errno 2] No such file or directory: 'baz' 

es posible que desee poner en un poco de esfuerzo poner en orden el mensaje de error, pero es posible que no vale la pena el esfuerzo.

+0

Me encantan los generadores ... –

+0

Tenga en cuenta, sin embargo, que atrapar 'IOError' atrapará e ignorará más que solo problemas de" archivo no existe ". Si el archivo existe, pero no es legible, nunca lo sabrá. Esto puede estar bien, por supuesto, dependiendo de la aplicación; sin embargo, si desea distinguir entre archivos inexistentes y errores al leer archivos existentes, capturar e ignorar 'IOError' no es el camino a seguir. –

+0

@Brian De hecho, pero en este caso diría que es una mejora sobre el "archivo no existe". – marcog

2

Usted puede resolver su problema con el módulo fileinput de la siguiente manera:

import fileinput 

input = fileinput.input() 
while True: 
    try: 
     process(input.next()) 
    except IOError: 
     input.nextfile() 
    except StopIteration: 
     break 

Lamentablemente no se puede utilizar para el bucle porque el IOException rompe.

+1

+1 para esto! La cláusula 'except' también debería hacer algo como' excepto IOError, e: sys.stderr.write ("% s:% s:% s \ n"% (sys.argv [0], input.filename(), os.strerror (e.errno))) 'antes del' nextfile() '. – tripleee

+0

+1 gracias JooMing, tripleee - útil para tener una solución que se quede con la entrada de archivos (cambio rápido y fácil a mi código existente) – azhrei

0

Intenté implementar la sugerencia de @ VGE, pero mi intento resultó no ser demasiado elegante. Agradecería cualquier sugerencia sobre cómo mejorar esto.

import sys, fileinput, errno, os 

class nosuchfile: 
    def readlines(foo, bar): 
     return [] 
    def close(arg): 
     pass 

EXITCODE=0 

def skip_on_error (filename, mode): 
    """Function to pass in as fileinput.input(openhook=...) hook function. 
    Instead of give up on the first error, skip the rest of the file and 
    continue with the next file in the input list. 

    In case of an error from open() an error message is printed to standard 
    error and the global variable EXITCODE gets overwritten by a nonzero 
    value. 
    """ 
    global EXITCODE 
    try: 
     return open(filename, mode) 
    except IOError, e: 
     sys.stderr.write ("%s: %s: %s\n" % (sys.argv[0], filename, os.strerror(e.errno))) 
     EXITCODE = 1 
     return nosuchfile() 

def main(): 
    do_stuff(fileinput.input(openhook=skip_on_error)) 
    return EXITCODE 

Tanto la clase gestor de archivo marcador de posición ficticia nosuchfile y la variable global EXITCODE son verrugas bastante graves. Traté de averiguar cómo pasar una referencia a una variable de código de acceso de ámbito local, pero me rendí.

Esto tampoco soluciona los errores que ocurren durante la lectura, pero la mayoría de los casos de error parecen ocurrir en open de todos modos.

Cuestiones relacionadas