• Home
  • Testimonials
  • Blog
  • Contact Us

At a Glance of a Key

Crafting Dreams into Ventures, Code into Excellence: Your Journey to Success

  • Home
  • Testimonials
  • Blog
  • Contact Us

Bash Tips & Tricks: Handling failures in pipe

2017-05-23 Tips & Tricks No Comments 3 minute read

If you’re using bash, you probably know that pipes are really nice and helpful. Recently I wasted a lot of time trying to realize why one of our tests failed on data corruption (we are kind-of a storage company so this is bad) and the results were amusing (or sad, you can decide).

The test is simple:

  1. Create a random file and calculate it’s MD5.
  2. Make some nasty stuff to our system.
  3. Read the file, recalculate it’s MD5 and make sure they are the same.

Well, they weren’t.

The first part of the test is done using the following command:

1
2
3
4
5
[21:00 alexander ~/tmp ]$ head -c 10485760 < /dev/urandom | tee outputfile | md5sum | awk '{print $1}'
fe187b9c6de9403eb493f5bcfc1e1c2c

[21:00 alexander ~/tmp ]$ echo $?
0

The verification part is done later on using the following command:

1
2
[21:00 alexander ~/tmp ]$ md5sum outputfile | awk '{print $1}'
fe187b9c6de9403eb493f5bcfc1e1c2c

As you can see, in this example, everything works fine.

Now, let’s simulate an error in the middle of the pipe by using a ram drive that is smaller than our write:

1
2
3
4
5
6
7
8
9
10
[21:01 alexander ~/tmp ]$ mkdir storage
[21:01 alexander ~/tmp ]$ sudo mount -t tmpfs -o size=5m tmpfs storage
[21:01 alexander ~/tmp ]$ head -c 10485760 < /dev/urandom | tee storage/outputfile | md5sum | awk '{print $1}'
tee: storage/outputfile: No space left on device
ce034de6ca47a9e63c8d2fb48de89c86
[21:01 alexander ~/tmp ]$ echo $?
0
[21:01 alexander ~/tmp ]$ md5sum storage/outputfile | awk '{print $1}'
59c6ddea9d614f1fb0df9d145857b246
[21:01 alexander ~/tmp ]$ sudo umount storage

As you can see, the first command wrote to stderr: “No space left on device” but the result of the command is 0. Then we continue the regular flow and see that the file signature is different.

This happens due to the fact that the result of the command is determined by the last ran sub-command, means that the $? variable will be set to the result of “awk”.

Bash gives us the option to “drag” the last failure to the result of the pipe by using the “pipefail” option:

Each command in a pipeline is executed in its own subshell (see Command Execution Environment). The exit status of a pipeline is the exit status of the last command in the pipeline, unless the pipefail option is enabled (see The Set Builtin). If pipefail is enabled, the pipeline’s return status is the value of the last (rightmost) command to exit with a non-zero status, or zero if all commands exit successfully. If the reserved word ‘!’ precedes the pipeline, the exit status is the logical negation of the exit status as described above. The shell waits for all commands in the pipeline to terminate before returning a value.

Here is a simple example (note that the pipe is ran in a sub-shell so the pipefail won’t affect the current shell):

1
2
3
4
5
6
[21:02 alexander ~/tmp ]$ false | true ; echo $?
0
[21:02 alexander ~/tmp ]$ (set -o pipefail && false | true ; echo $?)
1
[21:02 alexander ~/tmp ]$ false | true ; echo $?
0

Now, if we’ll go back to the original code snippet and use the flag there:

1
2
3
4
5
6
7
[21:03 alexander ~/tmp ]$ mkdir storage
[21:03 alexander ~/tmp ]$ sudo mount -t tmpfs -o size=5m tmpfs storage
[21:03 alexander ~/tmp ]$ (set -o pipefail && head -c 10485760 < /dev/urandom | tee storage/outputfile | md5sum | awk '{print $1}')
tee: storage/outputfile: No space left on device
ce034de6ca47a9e63c8d2fb48de89c86
[21:03 alexander ~/tmp ]$ echo $?
1

So we will fail the test on the “out of disk space” issue instead of looking for corruptions (or unicorns)…

– Alexander

Oh hi there 👋
It’s nice to meet you.

Sign up to receive a notification when new posts are published!

We don’t spam!

Check your inbox or spam folder to confirm your subscription.

Bash

Building simple url-redirection service using Flask and Python

Why you shouldn't trust the documentation ?

Leave a Reply Cancel reply

About Me

Principal Software Engineer and an industry leader with startup and FAANG experience. I specialize in distributed systems, storage, data protection services and payment processors.

Beyond technical expertise, I am passionate about supporting fellow engineers in their careers. Through approachable blogs and hands-on guidance, I help navigate the ever-evolving landscape of technology, empowering individuals to thrive in their professional journeys.

Open LinkedIn

Recent Posts

  • Building a Delayed Message System with Redis and FastAPI
  • Go Concurrency, Practical Example
  • Using GORM – Part 3: Models and Idempotency
  • Using GORM – Part 2: Transactions and Save Points
  • Using GORM – Part 1: Introduction

Archives

  • January 2025
  • December 2024
  • March 2023
  • February 2023
  • September 2022
  • July 2022
  • July 2021
  • June 2021
  • February 2021
  • April 2018
  • March 2018
  • January 2018
  • July 2017
  • June 2017
  • May 2017

Categories

  • AWS
  • Career Growth
  • Cyber Security
  • Debugging
  • Development
  • Storage
  • Tips & Tricks

Tags

API AWS Azure Bash Brainfuck C++ Challenge Cloud Cloud Bursting Concurrency Database DevOps Disassembly DLL Documentation DynamoDB Go Golang Guice Java Jenkins Mossad NoSQL OOP Performance Programming Python Redis Security Serverless Singleton Streams Testing Unit Tests WebService

All Rights Reserved 2025 © Sirotin Enterprises Inc.
Proudly powered by WordPress | Theme: Doo by ThemeVS.