programar - ¿Cómo leer desde stdin o desde un archivo si no se canalizan datos en Python?
python crear archivo html (6)
No hay una forma confiable de detectar si sys.stdin
está conectado a algo, ni es apropiado hacerlo (por ejemplo, el usuario quiere pegar los datos). Detecta la presencia de un nombre de archivo como argumento y usa stdin si no se encuentra ninguno.
Tengo un script de CLI y quiero que lea datos de un archivo. Debería poder leerlo de dos maneras:
cat data.txt | ./my_script.py
-
./my_script.py data.txt
—Un poco como grep
, por ejemplo.
Lo que yo sé:
-
sys.argv
yoptparse
me permiten leer cualquier argumento y opciones fácilmente. -
sys.stdin
me dejó leer los datos introducidos -
fileinput
hacer el proceso completo automático
Desafortunadamente:
- usando
fileinput
usa stdin y cualquier argumento como entrada. Así que no puedo usar opciones que no sean nombres de archivo cuando intenta abrirlos. -
sys.stdin.readlines()
funciona bien, pero si no canalizo ningún dato, se bloquea hasta que ingrese Ctrl + D - No sé cómo implementar "si no hay nada en la entrada estándar, lea de un archivo en args" porque la
stdin
siempre esTrue
en un contexto booleano.
Me gustaría una forma portátil de hacer esto si es posible.
Para Unix / Linux, puede detectar si los datos se están canalizando mirando os.isatty(0)
$ date | python -c "import os;print os.isatty(0)"
False
$ python -c "import os;print os.isatty(0)"
True
No estoy seguro de que haya un equivalente para Windows.
edit Ok, lo probé con python2.6 en Windows XP
C:/Python26>echo "hello" | python.exe -c "import os;print os.isatty(0)"
False
C:/Python26> python.exe -c "import os;print os.isatty(0)"
True
Así que tal vez no sea todo sin esperanza para las ventanas.
Procese sus argumentos sin nombre de archivo como desee, de modo que termine con una matriz de argumentos sin opción, luego pase esa matriz como parámetro a fileinput.input ():
import fileinput
for line in fileinput.input(remaining_args):
process(line)
Puede usar esta función para detectar si la entrada proviene de una tubería o no.
sys.stdin.isatty()
Devuelve false si la entrada es de pipeline o true de lo contrario.
Soy un noob, por lo que esta podría no ser una buena respuesta, pero estoy tratando de hacer lo mismo (permitir uno o más archivos en la línea de comandos, de manera predeterminada, STDIN).
El combo final que armé:
parser = argparse.ArgumentParser()
parser.add_argument("infiles", nargs="*")
args = parser.parse_args()
for line in fileinput.input(args.infiles):
process(line)
Esta parece ser la única forma de obtener todo el comportamiento deseado en un paquete elegante, sin requerir argumentos nombrados. Al igual que los comandos de Unix se utilizan como tales:
cat file1 file2
wc -l < file1
No:
cat --file file1 --file file2
Apreciaría la retroalimentación / confirmación de los veteranos pitonistas idiomáticos para asegurarse de que tengo la mejor respuesta. No he visto esta solución completa mencionada en ningún otro lugar, solo fragmentos.
Argparse permite que esto se haga de una manera bastante fácil, y realmente debería usarlo en lugar de optparse
menos que tenga problemas de compatibilidad.
El código iría algo como esto:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument(''--input'', type = argparse.FileType(''r''), default = ''-'')
Ahora tiene un analizador que analizará los argumentos de la línea de comando, use un archivo si lo ve, o use la entrada estándar si no lo hace.