Hello I need to grep the output from df. Sadly awk is not an option (even though its the easy option) here I can only use grep.

Filesystem           1K-blocks      Used Available Use% Mounted on
none                         4         0         4   0% /sys/fs/cgroup
none                      5120         0      5120   0% /run/lock
none                   1981488       444   1981044   0% /run/shm
none                    102400        64    102336   0% /run/user
/dev/sda3            418176236 281033024 137143212  67% /media/mark/7EE21FBAE21F761D

So for example I want the $4 column of the line beginning with /dev/sda3

  • 1
    On what operating system? There are tricks you can do but they depend on your grep implementation. Please always mention your OS. – terdon Sep 25 '14 at 10:51

If you have a version of grep that supports -P (perl-compatible regex, PCREs) and -o (print only the matching string), you can do

df | grep -oP '/sda3.* \K\d+(?=\s+\d+%)' 


Here, we match /sda3, then as many characters as possible until we find a stretch of numbers (\d+) which is followed by one or more spaces (\s+), then one or more numbers (\d+) and a %. The foo(?=bar) construct is a positive lookahead, it allows you to search for the string foo only if it is followed by the string bar. The \K is a PCRE trick that means "discard anything matched up to this point". Combined with -o, it lets you use strings that precede your pattern to anchor your match but not print them.

Without -P, things are trickier. You would need multiple passes. For example:

df | grep -o '/sda3.*%' | grep -Eo '[0-9]+ *[0-9]+%' | grep -Eo '^[0-9]+'


Here, the first grep identifies the right line and prints everything up to the %. The second prints the longest stretch of numbers before a space and another stretch of numbers ending with % and the final one prints the longest stretch of numbers found at the beginning of the line. Since the previous one only printed the free space and the percentage, this is the free space.

If your grep doesn't even support -E, you could do:

df | grep -o '/sda3.*%' | grep -o '[0-9]* *[0-9]*%' | grep -o '[0-9][0-9]* '


Here, we can't use + for "one or more" so, for the last grep, we need to specify at least one number, followed by 0 or more ([0-9][0-9]*).

If you can use other tools of course, things get much easier:

df | sed -n '/sda3/{s/  */ /gp}' | cut -d' ' -f4


The sed won't print anything (-n) unless the current line matches sda3 (/sda3/{}) and, if it does, it replaces all consecutive spaces with a single one, allowing the use of cut to print the 4th field.


df | perl -lne 'm#/sda3.+\s(\d+)\s+\d+%# && print $1' 


The -l adds a newline to each print call, the -n means "read the input line by line" and the -e lets you pass a script on the command line. The script itself matches sda3, then any stretch of characters up to whitespace followed by one or more numbers (\s(\d+)), then whitespace followed by a stretch of numbers ending with % (\s+\d+). The parentheses capture the part we are interested in which is then printed as $1.


df | tr -s ' ' $'\t' | grep sda3 | cut -f4


Here, we simply use tr to convert multiple consecutive spaces to a tab (the default delimiter of cut), then grep for sda3 and print the 4th field.


How to use grep to solve it as you ask is already anwered;
This answer is about how to solve the example problem - getting a separate value from df:

GNU df from coreutils has an option to specify the columns shown in the output:

$ df --output=avail /dev/sda3

Unfortunately, there is no option to suppress the column header - so it needs to be discarded in an extra step, with tail:

$ df --output=avail /dev/sda3 | tail -n 1

or grep, if you prefer:

$ df --output=avail /dev/sda3 | grep '[0-9]'

Depending on your grep version, you can also use -o for only and -E for extended regex.

So you can use

df | grep /dev/sda3 | grep -E -o "[[:digit:]]+[[:space:]]+[[:digit:]]+%" | grep -E -o ".+\s"

This needs the % char as an anchor for the first grep. After this you get the first chars until the space with the 2nd grep.

  • 2
    Nice, +1. Note, however, that this also includes the final space which might not be desired. – terdon Sep 25 '14 at 11:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.