How to read from a file or STDIN in Bash?

The following solution reads from a file if the script is called with a file name as the first parameter $1 otherwise from standard input.

while read line
do
  echo "$line"
done < "${1:-/dev/stdin}"

The substitution ${1:-...} takes $1 if defined otherwise the file name of the standard input of the own process is used.


Perhaps the simplest solution is to redirect stdin with a merging redirect operator:

#!/bin/bash
less <&0

Stdin is file descriptor zero. The above sends the input piped to your bash script into less's stdin.

Read more about file descriptor redirection.


Here is the simplest way:

#!/bin/sh
cat -

Usage:

$ echo test | sh my_script.sh
test

To assign stdin to the variable, you may use: STDIN=$(cat -) or just simply STDIN=$(cat) as operator is not necessary (as per @mklement0 comment).


To parse each line from the standard input, try the following script:

#!/bin/bash
while IFS= read -r line; do
  printf '%s\n' "$line"
done

To read from the file or stdin (if argument is not present), you can extend it to:

#!/bin/bash
file=${1--} # POSIX-compliant; ${1:--} can be used either.
while IFS= read -r line; do
  printf '%s\n' "$line" # Or: env POSIXLY_CORRECT=1 echo "$line"
done < <(cat -- "$file")

Notes:

- read -r - Do not treat a backslash character in any special way. Consider each backslash to be part of the input line.

- Without setting IFS, by default the sequences of Space and Tab at the beginning and end of the lines are ignored (trimmed).

- Use printf instead of echo to avoid printing empty lines when the line consists of a single -e, -n or -E. However there is a workaround by using env POSIXLY_CORRECT=1 echo "$line" which executes your external GNU echo which supports it. See: How do I echo "-e"?

See: How to read stdin when no arguments are passed? at stackoverflow SE

Tags:

Bash

Stdin