python - partir - Leer desde archivo, o STDIN
modificar txt python (7)
He escrito una utilidad de línea de comandos que usa getopt para analizar argumentos dados en la línea de comando. También me gustaría que un nombre de archivo sea un argumento opcional, como lo es en otras utilidades como grep, cut, etc. Por lo tanto, me gustaría que tenga el siguiente uso
tool -d character -f integer [filename]
¿Cómo puedo implementar lo siguiente?
- si se da un nombre de archivo, lee del archivo.
- si no se proporciona un nombre de archivo, lea de STDIN.
Algo como:
if input_from_file:
f = open(file_name, "rt")
else:
f = sys.stdin
inL = f.readline()
while inL:
print inL.rstrip()
inL = f.readline()
El módulo de entrada de fileinput puede hacer lo que quiera; suponiendo que los argumentos que no son de opción están en args
entonces:
import fileinput
for line in fileinput.input(args):
print line
Si args
está vacío, fileinput.input()
leerá desde stdin; de lo contrario, se lee de cada archivo uno por uno, de manera similar a Perl''s while(<>)
.
En los términos más simples:
import sys
# parse command line
if file_name_given:
inf = open(file_name_given)
else:
inf = sys.stdin
En este punto, usaría inf
para leer del archivo. Dependiendo de si se dio un nombre de archivo, esto se leería desde el archivo dado o desde stdin.
Cuando necesite cerrar el archivo, puede hacer esto:
if inf is not sys.stdin:
inf.close()
Sin embargo, en la mayoría de los casos será inofensivo cerrar sys.stdin
si ya ha terminado.
Me gusta el lenguaje general de usar un administrador de contexto, pero la solución (demasiado) trivial termina cerrando sys.stdin
cuando está fuera de la declaración with
, que quiero evitar.
Tomando prestado de esta respuesta , aquí hay una solución alternativa:
import sys
import contextlib
@contextlib.contextmanager
def _smart_open(filename, mode=''Ur''):
if filename == ''-'':
if mode is None or mode == '''' or ''r'' in mode:
fh = sys.stdin
else:
fh = sys.stdout
else:
fh = open(filename, mode)
try:
yield fh
finally:
if filename is not ''-'':
fh.close()
if __name__ == ''__main__'':
args = sys.argv[1:]
if args == []:
args = [''-'']
for filearg in args:
with _smart_open(filearg) as handle:
do_stuff(handle)
Supongo que podrías lograr algo similar con os.dup()
pero el código que os.dup()
para hacer eso resultó ser más complejo y más mágico, mientras que lo anterior es un tanto torpe pero muy directo.
No respuesta directa pero relacionada.
Normalmente, cuando escribe un script de python puede usar el paquete argparse
. SI este es el caso que puede usar:
parser = argparse.ArgumentParser()
parser.add_argument(''infile'', nargs=''?'', type=argparse.FileType(''r''), default=sys.stdin)
''?''. De ser posible, se consumirá un argumento de la línea de comando y se producirá como un único elemento. Si no hay un argumento de línea de comandos presente, se generará el valor predeterminado.
y aquí establecemos el valor predeterminado para sys.stdin
;
entonces, si hay un archivo, lo leerá, y si no, tomará la entrada de stdin "Nota: que estamos usando un argumento posicional en el ejemplo anterior"
para obtener más visita: https://docs.python.org/2/library/argparse.html#nargs
Para hacer uso de la declaración de python with
, uno puede usar el siguiente código:
import sys
with open(sys.argv[1], ''r'') if len(sys.argv) > 1 else sys.stdin as f:
# read data using f
# ......
Prefiero usar "-" como indicador de que debe leer de stdin, es más explícito:
import sys
with open(sys.argv[1], ''r'') if sys.argv[1] is not "-" else sys.stdin as f:
pass # do something here