variable una sirve script que programas programacion pasar parametros para funciones ejemplos crear con bash pipe stdin

sirve - ¿Cómo hacer una función bash que pueda leer desde la entrada estándar?



pasar parametros shell script (5)

Tengo algunos scripts que funcionan con parámetros, funcionan bien, pero me gustaría que sean capaces de leer desde stdin, desde un conducto, por ejemplo, un ejemplo, supongamos que esto se llama leer:

#!/bin/bash function read() { echo $* } read $*

Ahora esto funciona con read "foo" "bar" , pero me gustaría usarlo como:

echo "foo" | read

¿Cómo logro esto?


Aquí hay ejemplos de implementación de la función sprintf en bash que usa printf y entrada estándar:

sprintf() { local stdin; read -d '''' -u 0 stdin; printf "$@" "$stdin"; }

Ejemplo de uso:

$ echo bar | sprintf "foo %s" foo bar

Esto le daría una idea de cómo la función puede leer desde la entrada estándar.


Descubrí que esto se puede hacer en una línea usando test y awk ...

test -p /dev/stdin && awk ''{print}'' /dev/stdin

La test -p prueba la entrada en una tubería, que acepta la entrada a través de stdin. Solo si la entrada está presente, queremos ejecutar el awk ya que de lo contrario se colgará indefinidamente esperando una entrada que nunca llegará.

Puse esto en una función para que sea fácil de usar ...

inputStdin () { test -p /dev/stdin && awk ''{print}'' /dev/stdin && return 0 ### accepts input if any but does not hang waiting for input # return 1 }

Uso...

_stdin="$(inputStdin)"

Otra función utiliza awk sin la prueba para esperar la entrada de la línea de comandos ...

inputCli () { local _input="" local _prompt="$1" # [[ "$_prompt" ]] && { printf "%s" "$_prompt" > /dev/tty; } ### no prompt at all if none supplied # _input="$(awk ''BEGIN {getline INPUT < "/dev/tty"; print INPUT}'')" ### accept input (used in place of ''read'') ### put in a BEGIN section so will only accept 1 line and exit on ENTER ### WAITS INDEFINITELY FOR INPUT # [[ "$_input" ]] && { printf "%s" "$_input"; return 0; } # return 1 }

Uso...

_userinput="$(inputCli "Prompt string: ")"

Tenga en cuenta que el > /dev/tty en la primera impresiónf parece ser necesario para hacer que el prompt se imprima cuando se invoca la función en un Command Substituion $(...) .

Este uso de awk permite la eliminación del peculiar comando de read para recopilar información desde el teclado o stdin.


Es un poco complicado escribir una función que puede leer la entrada estándar, pero funciona correctamente cuando no se proporciona una entrada estándar. Si simplemente intenta leer desde la entrada estándar, se bloqueará hasta que reciba alguno, al igual que si simplemente escribe cat en el aviso.

En bash 4, puede solucionar esto utilizando la opción -t para read con un argumento de 0. Tiene éxito si hay alguna entrada disponible, pero no consume nada de ella; de lo contrario, falla.

Aquí hay una función simple que funciona como cat si tiene algo de entrada estándar, y echo contrario.

catecho () { if read -t 0; then cat else echo "$*" fi } $ catecho command line arguments command line arguments $ echo "foo bar" | catecho foo bar

Esto hace que la entrada estándar tenga prioridad sobre los argumentos de la línea de comandos, es decir, echo foo | catecho bar echo foo | catecho bar saldría foo . Para hacer que los argumentos tengan prioridad sobre la entrada estándar ( echo foo | catecho bar salidas echo foo | catecho bar bar ), puede usar la función más simple

catecho () { if [ $# -eq 0 ]; then cat else echo "$*" fi }

(que también tiene la ventaja de trabajar con cualquier shell compatible con POSIX, no solo con ciertas versiones de bash ).


Para combinar un número de otras respuestas en lo que funcionó para mí (este ejemplo ideado convierte mayúsculas a minúsculas):

uppercase() { local COMMAND=''tr [:lower:] [:upper:]'' if [ -t 0 ]; then if [ $# -gt 0 ]; then echo "$*" | ${COMMAND} fi else cat - | ${COMMAND} fi }

Algunos ejemplos (el primero no tiene entrada, y por lo tanto no tiene salida):

:; uppercase :; uppercase test TEST :; echo test | uppercase TEST :; uppercase <<< test TEST :; uppercase < <(echo test) TEST

Paso a paso:

  • prueba si el descriptor de archivo 0 ( /dev/stdin ) fue abierto por un terminal

    if [ -t 0 ]; then

  • pruebas para argumentos de invocación de CLI

    if [ $# -gt 0 ]; then

  • hacer eco de todos los argumentos CLI al comando

    echo "$*" | ${COMMAND}

  • de lo contrario, si stdin se canaliza (es decir, no es entrada de terminal), la salida stdin al comando ( cat - y cat son la abreviatura de cat /dev/stdin )

    else cat - | ${COMMAND}


Puedes usar <<< para obtener este comportamiento. read <<< echo "text" debería hacerlo.

Prueba con readly (prefiero no usar palabras reservadas):

function readly() { echo $* echo "this was a test" } $ readly <<< echo "hello" hello this was a test

Con pipes, basado en esta respuesta a "Bash script, lea los valores de stdin pipe" :

$ echo "hello bye" | { read a; echo $a; echo "this was a test"; } hello bye this was a test