1. Overview

The strace command can help us diagnose and trace system calls and signals.

In this quick tutorial, we’ll discuss how to filter strace‘s output using grep.

2. Introduction to the Problem

strace is a diagnostic utility. It can trace system calls to a command. Let’s take the awk  command as an example:

$ strace awk 'BEGIN{print "hello world"}'
execve("/usr/bin/awk", ["awk", "BEGIN{print \"hello world\"}"], 0x7ffe4ae1eea8 /* 91 vars */) = 0
brk(NULL)                               = 0x17b8000
arch_prctl(0x3001 /* ARCH_??? */, 0x7ffde42239c0) = -1 EINVAL (Invalid argument)
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f12f002a000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
...
getpgrp() = 25538
getpid() = 25541
getppid() = 25538
getuid() = 1000
geteuid() = 1000
getgid() = 1000
getegid() = 1000
...

As we can see, the strace command produces a lot of output. Usually, we may only want to focus on particular system calls. For example, let’s say we’d like to filter all get*() calls, and check whether they return expected values, such as getuid(), getgid(), and so on.

When we need to filter one command’s output, we often pipe the output to the grep command. So next, let’s give it a try:

$ strace awk 'BEGIN{print "hello world"}' | grep 'get[^(]*()'    
execve("/usr/bin/awk", ["awk", "BEGIN{print \"hello world\"}"], 0x7fff27249b48 /* 91 vars */) = 0
brk(NULL)
arch_prctl(0x3001 /* ARCH_??? */, 0x7fffd8a11230) = -1 EINVAL (Invalid argument)
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f8e0747f000
...

As we can see in the output above, grep‘s text filtering doesn’t work, although we pipe strace‘s output to it. So instead, we’ve got a similar output as the previous command without grep.

Next, let’s figure out why this happens and discuss the right way to filter strace‘s output using the grep command.

3. Redirecting Standard Error to Standard Output

To figure out why the command “strace … | grep …” doesn’t work as expected, we need to understand what the pipe does in the command.

In the Linux command line, we know that the pipe operator allows us to use the output of one command as the input to the next command, such as CMD1 | CMD2.

There are three standard file descriptors in Linux. The standard input (stdin) is the file descriptor 0, the standard output (stdout) is the file descriptor 1, and the standard error (stderr) is the file descriptor 2.

In the command “CMD1 | CMD2“, the pipe operator takes CMD1‘s stdout as CMD2‘s stdin.

Further, the strace command produces output to stderr instead of stdout. Therefore, the filtering won’t work if we pipe strace‘s stdout to grep.

One straightforward way to solve the problem is to redirect strace‘s stderr to stdout before piping to grep using the ‘>‘ operator:

$ strace awk 'BEGIN{print "hello world"}' 2>&1 | grep 'get[^(]*()'
getpgrp()                               = 26552
getpid()                                = 26556
getppid()                               = 26552
getuid()                                = 1000
geteuid()                               = 1000
getgid()                                = 1000
getegid()                               = 1000

As we can see, we’ve got the filtered result. “2>&1” in the command above means we redirect the file descriptor 2 (stderr) to the file descriptor 1 (stdout).

Alternatively, we can use process substitution to achieve that:

$ grep 'get[^(]*()' <(strace awk 'BEGIN{print "hello world"}' 2>&1)               
getpgrp()                               = 35545
getpid()                                = 35549
getppid()                               = 35545
getuid()                                = 1000
geteuid()                               = 1000
getgid()                                = 1000
getegid()                               = 1000

4. Conclusion

In this article, we’ve discussed how to use the grep command to filter strace‘s output.

As strace writes output to stderr, we need to redirect strace‘s stderr to stdout to feed the grep command.

Comments are closed on this article!