El siguiente script de Perl ( my.pl
) puede leer desde el archivo en la línea de comando args o desde STDIN:
while (<>) {
print($_);
}
perl my.pl
leerá de STDIN, mientras perl my.pl a.txt
que leerá de a.txt
. Esto es muy conveniente.
¿Se pregunta si hay un equivalente en Bash?
/proc/$$/fd/0
y/dev/stdin
? Me di cuenta de que este último parece ser más común y parece más sencillo.-r
a suread
comando, para que no coma\
caracteres accidentalmente ; usewhile IFS= read -r line
para preservar los espacios en blanco iniciales y finales./bin/sh
: ¿está utilizando un shell diferente debash
osh
?Quizás la solución más simple es redirigir stdin con un operador de redirección de fusión:
Stdin es el descriptor de archivo cero. Lo anterior envía la entrada canalizada a su script bash en el stdin de less.
Lea más sobre la redirección del descriptor de archivo .
fuente
<&0
de esta situación no tiene ningún beneficio : su ejemplo funcionará igual con o sin él; aparentemente, las herramientas que invoca desde un script bash de manera predeterminada ven el mismo stdin que el script en sí (a menos que el script lo consuma primero).Aquí está la forma más simple:
Uso:
Para asignar stdin a la variable, puede usar:
STDIN=$(cat -)
o simplementeSTDIN=$(cat)
como operador no es necesario (según el comentario de @ mklement0 ).Para analizar cada línea desde la entrada estándar , pruebe el siguiente script:
Para leer del archivo o stdin (si el argumento no está presente), puede extenderlo a:
Ver: ¿Cómo leer stdin cuando no se pasan argumentos? en stackoverflow SE
fuente
[ "$1" ] && FILE=$1 || FILE="-"
aFILE=${1:--}
. (Quibble: mejor para evitar todas-mayúsculas cáscara variables en colisiones de nombres Evitar en caso de ambiente variables.)${1:--}
es compatible con POSIX, por lo que debería funcionar en todos los shells similares a POSIX. Lo que no funcionará en todos estos shells es la sustitución de procesos (<(...)
); funcionará en bash, ksh, zsh, pero no en el tablero, por ejemplo. Además, es mejor agregar-r
a suread
comando, para que no coma\
caracteres accidentalmente ; anteponerIFS=
para preservar los espacios en blanco iniciales y finales.echo
: si una línea consiste en-e
,-n
o-E
, no se mostrará. Para solucionar este problema, debe utilizarprintf
:printf '%s\n' "$line"
. No lo incluí en mi edición anterior ... con demasiada frecuencia mis ediciones se revierten cuando soluciono este error:(
.--
es inútil si el primer argumento es'%s\n'
IFS=
conread
y enprintf
lugar deecho
.:)
.Creo que este es el camino directo:
-
-
fuente
read
se lee de la entrada estándar por defecto , por lo que no hay necesidad de< /dev/stdin
.La
echo
solución agrega nuevas líneas cada vez queIFS
rompe el flujo de entrada. La respuesta de @ fgm se puede modificar un poco:fuente
read
's comportamiento: mientrasread
no potencialmente dividido en varias fichas de los caracteres. contenido$IFS
, solo devuelve un token único si solo especifica un nombre de variable único (pero recorta y espacios en blanco iniciales y finales de forma predeterminada).read
y agrega nuevas líneas sin la bandera. "La utilidad echo escribe los operandos especificados, separados por caracteres en blanco (` ') y seguidos por un carácter de nueva línea (`\ n'), en la salida estándar".$IFS
echo
-n
\n
agregado porecho
: Perl$_
incluye la línea que termina\n
desde la línea leída, mientras que bashread
no. (Sin embargo, como @gniourf_gniourf señala en otra parte, el enfoque más robusto es usarprintf '%s\n'
en lugar deecho
).El bucle Perl en la pregunta se lee de todos los argumentos de nombre de archivo en la línea de comando, o de la entrada estándar si no se especifican archivos. Las respuestas que veo parecen procesar un solo archivo o entrada estándar si no se especifica ningún archivo.
Aunque a menudo se ridiculiza con precisión como UUOC (uso inútil de
cat
), hay momentos en quecat
es la mejor herramienta para el trabajo, y es discutible que esta sea una de ellas:El único inconveniente de esto es que crea una tubería que se ejecuta en un sub-shell, por lo que cosas como asignaciones de variables en el
while
bucle no son accesibles fuera de la tubería. Labash
forma de evitarlo es la sustitución de procesos :Esto deja el
while
ciclo ejecutándose en el shell principal, por lo que las variables establecidas en el ciclo son accesibles fuera del ciclo.fuente
>>EOF\n$(cat "$@")\nEOF
. Finalmente, una objeción:while IFS= read -r line
es una mejor aproximación de lo quewhile (<>)
hace en Perl (conserva los espacios en blanco iniciales y finales, aunque Perl también mantiene el final\n
).El comportamiento de Perl, con el código dado en el OP, puede tomar ninguno o varios argumentos, y si un argumento es un guión simple,
-
esto se entiende como stdin. Además, siempre es posible tener el nombre de archivo con$ARGV
. Ninguna de las respuestas dadas hasta ahora realmente imita el comportamiento de Perl en estos aspectos. Aquí hay una posibilidad pura de Bash. El truco es usarloexec
apropiadamente.Nombre de archivo disponible en
$1
.Si no se dan argumentos, los establecemos artificialmente
-
como el primer parámetro posicional. Luego hacemos un bucle en los parámetros. Si un parámetro no es-
, redirigimos la entrada estándar del nombre del archivo conexec
. Si esta redirección tiene éxito, hacemos un bucle con unwhile
bucle. Estoy usando laREPLY
variable estándar , y en este caso no es necesario reiniciarIFS
. Si desea otro nombre, debe restablecerloIFS
así (a menos que, por supuesto, no lo desee y sepa lo que está haciendo):fuente
Con más precisión...
fuente
IFS=
y-r
alread
comando asegura que cada línea se lea sin modificaciones (incluidos los espacios en blanco iniciales y finales).Por favor, intente el siguiente código:
fuente
read
sinIFS=
y-r
, y al pobre$line
sin sus citas saludables.read -r
notación. OMI, POSIX se equivocó; la opción debe habilitar el significado especial para las barras invertidas finales, no deshabilitarlo, de modo que los scripts existentes (anteriores a POSIX existieran) no se romperían porque-r
se omitió. Sin embargo, observo que era parte de IEEE 1003.2 1992, que era la primera versión del estándar POSIX de shell y utilidades, pero se marcó como una adición incluso entonces, por lo que esto es una queja sobre las oportunidades perdidas. Nunca he tenido problemas porque mi código no se usa-r
; Debo tener suerte. Ignórame sobre esto.-r
debería ser estándar. Estoy de acuerdo en que es poco probable que ocurra en los casos en que no usarlo ocasione problemas. Sin embargo, el código roto es un código roto. Mi edición se activó por primera vez por esa$line
variable pobre que perdió sus comillas. Lo arregléread
mientras estaba en eso. No arreglé elecho
porque ese es el tipo de edición que se revierte.:(
.Code
${1:-/dev/stdin}
solo entenderá el primer argumento, entonces, ¿qué tal esto?fuente
No encuentro ninguna de estas respuestas aceptables. En particular, la respuesta aceptada solo maneja el primer parámetro de línea de comando e ignora el resto. El programa Perl que está tratando de emular maneja todos los parámetros de la línea de comandos. Entonces la respuesta aceptada ni siquiera responde la pregunta. Otras respuestas usan extensiones bash, agregan comandos 'cat' innecesarios, solo funcionan para el caso simple de hacer eco de entrada a salida, o simplemente son innecesariamente complicados.
Sin embargo, tengo que darles algo de crédito porque me dieron algunas ideas. Aquí está la respuesta completa:
fuente
Combiné todas las respuestas anteriores y creé una función de shell que se adaptaría a mis necesidades. Esto es de un terminal cygwin de mis 2 máquinas con Windows10 donde tenía una carpeta compartida entre ellas. Necesito poder manejar lo siguiente:
cat file.cpp | tx
tx < file.cpp
tx file.cpp
Cuando se especifica un nombre de archivo específico, necesito usar el mismo nombre de archivo durante la copia. Cuando se ha canalizado el flujo de datos de entrada, entonces necesito generar un nombre de archivo temporal que tenga la hora minuto y segundo. La carpeta principal compartida tiene subcarpetas de los días de la semana. Esto es para fines organizativos.
He aquí, el último guión para mis necesidades:
Si hay alguna forma en que pueda ver para optimizar aún más esto, me gustaría saber.
fuente
Lo siguiente funciona con estándar
sh
(Probado condash
Debian) y es bastante legible, pero eso es cuestión de gustos:Detalles: si el primer parámetro no está vacío, entonces
cat
ese archivo, de lo contrariocat
, entrada estándar. Luego, la salida de toda laif
declaración es procesada porcommands_and_transformations
.fuente
cat "${1:--}" | any_command
. Leer a las variables de shell y hacer eco de ellas puede funcionar para archivos pequeños, pero no escala tan bien.[ -n "$1" ]
puede ser simplificado a[ "$1" ]
.Este es fácil de usar en la terminal:
fuente
Qué tal si
fuente
cat
se colocará en la línea de comando. La línea de comando tiene un tamaño máximo. Además, esto no se leerá línea por línea, sino palabra por palabra.