Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make a bash function which can read from standard input?

Tags:

bash

stdin

pipe

I have some scripts that work with parameters, they work just fine but i would like them to be able to read from stdin, from a pipe for example, an example, suppose this is called read:

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

Now this works with read "foo" "bar", but I would like to use it as:

echo "foo" | read 

How do I accomplish this?

like image 364
JBoy Avatar asked Sep 12 '13 10:09

JBoy


People also ask

What is standard input in Bash?

Bash Redirection STDIN, STDOUT and STDERR explained Standard input is used to provide input to a program. (Here we're using the read builtin to read a line from STDIN.) STDOUT root@server~# ls file file. Standard output is generally used for "normal" output from a command.

Which Bash command allows you to read input from stdin?

What is read? Read is a bash builtin command that reads the contents of a line into a variable. It allows for word splitting that is tied to the special shell variable IFS. It is primarily used for catching user input but can be used to implement functions taking input from standard input.

How do you pass a value to a function in Bash?

To pass any number of arguments to the bash function simply put them right after the function's name, separated by a space. It is a good practice to double-quote the arguments to avoid the misparsing of an argument with spaces in it. The passed parameters are $1 , $2 , $3 …


2 Answers

It's a little tricky to write a function which can read standard input, but works properly when no standard input is given. If you simply try to read from standard input, it will block until it receives any, much like if you simply type cat at the prompt.

In bash 4, you can work around this by using the -t option to read with an argument of 0. It succeeds if there is any input available, but does not consume any of it; otherwise, it fails.

Here's a simple function that works like cat if it has anything from standard input, and echo otherwise.

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

This makes standard input take precedence over command-line arguments, i.e., echo foo | catecho bar would output foo. To make arguments take precedence over standard input (echo foo | catecho bar outputs bar), you can use the simpler function

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

(which also has the advantage of working with any POSIX-compatible shell, not just certain versions of bash).

like image 127
chepner Avatar answered Sep 28 '22 04:09

chepner


You can use <<< to get this behaviour. read <<< echo "text" should make it.

Test with readly (I prefer not using reserved words):

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

With pipes, based on this answer to "Bash script, read values from stdin pipe":

$ echo "hello bye" | { read a; echo $a;  echo "this was a test"; } hello bye this was a test 
like image 33
fedorqui 'SO stop harming' Avatar answered Sep 28 '22 03:09

fedorqui 'SO stop harming'