A photo of Mitesh Shah

Mitesh Shah

Linux Expert | Automation Enthusiast | Security Consultant

Email Skype Github Twitter Resume Hire Me Keybase LinkedIn Stackoverflow

Standard IO & Pipes


Standard Input and Output

  • Linux provides three I/O channels to the programs.
    1. Standard Input (STDIN), File Descriptor Number 0, By Default Keyboard
    2. Standard Output (STDOUT), File Descriptor Number 1, By Default Screen or Terminal Window
    3. Standard Error (STDERR), File Descriptor Number 2, By Default Screen or Terminal Window


command operator filename

Supported Operators

  • > Redirect STDOUT to File
  • 2> Redirect STDERR to File
  • &> Redirect All Output (STDOUT and STDERR)

NOTE!: File contents are overwritten by default. Use >> to appends.

Redirecting Output to File

  • STDOUT and STDERR can be redirected to files.


* command < file                Send file as a Input to the command.
* command > file		Redirect STDOUT of command to file.
* command >> file		Append STDOUT of command to file.
* command 2> file		Redirect STDERR of command to file.
* command 2>> file    	        Append STDERR of command to file.

Run the following command as a non-root user

[mitesh@Matrix ~]$ find /etc -name passwd
find: `/etc/dhcp': Permission denied
find: `/etc/lvm': Permission denied
...output truncated...

Note what happens when the same command is run but STDOUT is redirected to a file

[mitesh@Matrix ~]$ find /etc -name passwd > find.out
find: `/etc/dhcp': Permission denied
...output truncated...

[mitesh@Matrix ~]$ cat find.out

NOTE!: The STDOUT and STDERR are distinct, Redirecting one does not affect the other.

The following command would redirect STDERR to a file

[mitesh@Matrix ~]$ find /etc -name passwd 2> find.err
  • The above command only show the STDOUT of the command.
  • If you really do not care about the errors then why you waste a file (find.err)?
  • There is a special file on your system that is very useful in this sort of situation, /dev/null.
  • /dev/null is a black hole for data. Anything sent to is simply ignored.

Display only STDOUT

[mitesh@Matrix ~]$ find /etc -name passwd 2> /dev/null

Store STDOUT but ignore STDERR

[mitesh@Matrix ~]$ find /etc -name passwd > find.out 2> /dev/null

Guess what happen when run the following command

[mitesh@Matrix ~]$ find /etc -name passwd > find.out 2> find.err
[mitesh@Matrix ~]$ find /etc -name passwd >> find.out 2>> find.err

Redirecting Output to Program

  • Linux and UNIX provides many small utilities that perform one task very well.
  • A core design feature of Linux and UNIX is that the output of one command can be fed directly as a input for another command.
  • Pipes can connect the commands.
command1 | command2
command1 | command2 | command3...

NOTE!: STDERR is not forwarded across the pipes.


[mitesh@Matrix man]$ pwd

[mitesh@Matrix man]$ ls -C | tr 'a-z' 'A-Z'

In the above example, All the lower case letters are converted to upper case letters

less - View input one page at a time

[mitesh@Matrix ~]$ ls -l /etc | less
Note: Input can be searched with /

mail - Send input via email

[mitesh@Matrix ~]$ echo "Test Email" | mail -s "Testing Mail" user@example.com

lpr - Send input to a printer

[mitesh@Matrix ~]$ echo "Test Printer" | lpr
[mitesh@Matrix ~]$ echo "Test Printer" | lpr -P printer_name

Redirecting All Output

  • Some operators affect both STDOUT and STDERR
  • &> Redirect All Output (STDOUT and STDERR)
[mitesh@Matrix ~]$ find /etc -name passwd &> find.all

Redirecting I/O Channels to Each Other

  • Run the following command as a non-root user:
[mitesh@Matrix ~]$ find /etc -name passwd | less
  • You will find that while STDOUT is display through less, STDERR is not.
  • This is because a pipe only redirect STDOUT.
  • If you wanted to send all output to less you would needed to redirect STDERR to STDOUT first.
  • You can redirect one I/O channel to another using > and the channel’s file descriptor numbers.

For Example:

[mitesh@Matrix ~]$ find /etc -name passwd 2>1
  • The above command simply redirect all STDERR to a file called 1 rather than to file descriptor 1 (STDOUT).
  • To tell your shell that you are referring to a file descriptor, prepend the &

For Example:

[mitesh@Matrix ~]$ find /etc -name passwd 2>&1 | less

Combining Outputs

  • Suppose you wanted to run two command back to back and send their output through the pipe.

For Example:

[mitesh@Matrix ~]$ cal 2014; cal 2015 | lpr
  • The output of these commands, you would find that only the calendar for 2015 was printed, while the calendar for 2014 went to the screen

  • This can be overcome by running the cal command in a subshell.

[mitesh@Matrix ~]$ (cal 2011; cal 2012) | lpr

Redirecting to Multiple Target


command1 | tee filename | command2
  • Stores STDOUT of command1 in filename, then pipes to command2


  • Troubleshooting complex pipelines.
  • Simultaneous viewing and logging of output


[mitesh@Matrix ~]$ ls -lR /etc | tee stage1.out | sort | tee stage2.out | uniq -c | tee stage3.out | sort -r | tee stage4.out | less
[mitesh@Matrix work]$ generate_report.sh | tee report.txt

Redirecting STDIN from a file

  • Redirect STDIN with <


[mitesh@Matrix work]$ tr 'A-Z' 'a-z' < .bash_profile
[mitesh@Matrix work]$ cat .bash_profile | tr 'A-Z' 'a-z'

[mitesh@Matrix work]$ cat filename.txt
Hello, World!
[mitesh@Matrix work]$ cat < filename.txt
Hello, World!

Sending Multiple Lines to STDIN

  • Redirect Multiple line from keyboard to STDIN with <<WORD
  • All text untill WORD is sent to STDIN.
  • Sometimes called heretext


[mitesh@Matrix work]$ mail -s "Please call" jane@example.com <<END
> Hi Jane,
> Please give me a call when you get in. We may need to do some maintenance on server1.
> Details when you're on-site,
> Boris

For Loop - Shell Scripting

  • Performs actions on each member of a set of values.


for variable in value1 value2...
  command using $variable


for NAME in root neo mitesh
  MESSAGE='Projects are due today!'
  echo $MESSAGE | mail-s Reminder $ADDRESS
for USER in $(grep bash /etc/passwd)...
for FILE in *.txt...

for num in {1..10}
for num in $(seq 1 10)
for num in $(seq 0 10 100)
# alive2.sh
# Check to see if hosts are alive

for n in {1..255}
  ping -c2 $host &> /dev/null

  if [ $? = 0 ]; then
    echo "$host is UP"
    echo "$host is DOWN"

Post Navigation