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.plleerá de STDIN, mientras perl my.pl a.txtque leerá de a.txt. Esto es muy conveniente.
¿Se pregunta si hay un equivalente en Bash?

/proc/$$/fd/0y/dev/stdin? Me di cuenta de que este último parece ser más común y parece más sencillo.-ra sureadcomando, para que no coma\caracteres accidentalmente ; usewhile IFS= read -r linepara preservar los espacios en blanco iniciales y finales./bin/sh: ¿está utilizando un shell diferente debashosh?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
<&0de 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-ra sureadcomando, para que no coma\caracteres accidentalmente ; anteponerIFS=para preservar los espacios en blanco iniciales y finales.echo: si una línea consiste en-e,-no-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=conready enprintflugar deecho.:).Creo que este es el camino directo:
-
-
fuente
readse lee de la entrada estándar por defecto , por lo que no hay necesidad de< /dev/stdin.La
echosolución agrega nuevas líneas cada vez queIFSrompe el flujo de entrada. La respuesta de @ fgm se puede modificar un poco:fuente
read's comportamiento: mientrasreadno 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).ready 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".$IFSecho-n\nagregado porecho: Perl$_incluye la línea que termina\ndesde la línea leída, mientras que bashreadno. (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 quecates 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
whilebucle no son accesibles fuera de la tubería. Labashforma de evitarlo es la sustitución de procesos :Esto deja el
whileciclo 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 linees 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 usarloexecapropiadamente.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 unwhilebucle. Estoy usando laREPLYvariable estándar , y en este caso no es necesario reiniciarIFS. Si desea otro nombre, debe restablecerloIFSasí (a menos que, por supuesto, no lo desee y sepa lo que está haciendo):fuente
Con más precisión...
fuente
IFS=y-ralreadcomando 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
readsinIFS=y-r, y al pobre$linesin sus citas saludables.read -rnotació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-rse 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.-rdeberí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$linevariable pobre que perdió sus comillas. Lo arregléreadmientras estaba en eso. No arreglé elechoporque 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 | txtx < file.cpptx file.cppCuando 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 condashDebian) y es bastante legible, pero eso es cuestión de gustos:Detalles: si el primer parámetro no está vacío, entonces
catese archivo, de lo contrariocat, entrada estándar. Luego, la salida de toda laifdeclaració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
catse 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.