Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

This question already has an answer here:

Consider the following output from df.

Filesystem      Size  Used Avail Use% Mounted on
/dev/sda1        23G  6.1G   16G  29% /
udev             10M     0   10M   0% /dev
tmpfs           397M  420K  397M   1% /run
tmpfs           5.0M     0  5.0M   0% /run/lock
tmpfs           1.8G  904K  1.8G   1% /run/shm
/dev/sda6       890G  324G  521G  39% /home
/dev/sdb1       459G  267G  169G  62% /home/user/mnt
none            4.0K     0  4.0K   0% /sys/fs/cgroup

How can I only show lines that begin with "/dev" and keep the heading, but filter out everything else. I'd also like to not have to resort to using using temporary files or variables? Note: the heading is locale dependent, therefore you can't catch it with a regexp.

share|improve this question

marked as duplicate by Mikel, Anthon, jasonwryan, rahmu, slm Feb 2 at 20:35

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

    
locale dependant maybe, but your can force the language with LANG=C df. –  Totor Dec 19 '13 at 15:46
    
@Totor see 1_CR's answer, that's exactly what he suggested. –  terdon Dec 19 '13 at 15:50
    
This has been answered several times previously. See e.g. body from unix.stackexchange.com/a/11859/3169 –  Mikel Feb 2 at 19:46
add comment

9 Answers 9

up vote 27 down vote accepted

I would use a slightly more sophisticated approach than simple grep:

  1. awk

    df -h | awk 'NR==1 || /^\/dev/'
    

    NR is the current line number so the awk scriptlet above will print if this is the first line or if the current line begins with /dev. And after posting this I see it is the same as @1_CR's answer. Oh well...

  2. Perl

    df -h | perl -ne 'print if (/^\/dev/ || $.==1)'
    

    The same idea here, in Perl the special variable $. is the current line number. An alternative way would be

    df -h | perl -pe '$_="" unless /^\/dev/ || $.==1'
    

    The -p switch will print all lines of the input file. The value of the current line is held in $_ so we set $_ to empty unless we want the current line.

  3. sed

    df -h | sed -n '1p; /^\/dev/p'
    

    The -n suppresses normal output so no lines are printed. The 1p means print the first line and the /^\/dev/p means print any line that starts with /dev.

    As pointed out in the comments below, in the unlikely case where the locale on your current system causes the header line to start with /dev, the command above will print it twice. Stephane Chazelas points out that this one will not have that problem:

    df -h | sed  -e 1b -e '/^\/dev/!d'
    
  4. grep

    df -h | grep -E '^(/dev|File)'
    

    This might not be portable because of LOCALE problems as you said. However, I am reasonably certain that no locale or df version will give a path in the first line, so searching for lines that contain no / should also work:

    df -h | grep -E '^[^/]*$|^/dev'
    
share|improve this answer
    
Your sed one would print the 1st line twice if it started with /dev. Unlikely, but sed -e 1b -e '/^\/dev/!d' wouldn't have the problem. –  Stéphane Chazelas Dec 18 '13 at 18:31
    
@StephaneChazelas thanks, answer edited. –  terdon Dec 18 '13 at 18:35
add comment

You are going to run into issues attempting to parse df output, however for simple cases, the following may work

LC_ALL=C df -P | awk 'NR == 1 || /^\/dev/' 
share|improve this answer
    
+1 Nice locale-independent solution! –  l0b0 Dec 19 '13 at 11:52
add comment
df -h | tee >(head -1) >(grep ^/dev) > /dev/null
share|improve this answer
2  
I just tried that; it printed the header line first. –  Keith Thompson Dec 18 '13 at 19:15
1  
@KeithThompson Why is that a problem? The accepted answers also print the header line first. –  l0b0 Dec 19 '13 at 11:49
    
@l0b0: Sorry, I mistyped; it printed the header line last. –  Keith Thompson Dec 19 '13 at 16:00
    
Worked correcly on my machine. Try df -h | tee >(head -1) >(sleep 0.5;grep ^/dev) > /dev/null;sleep 1.0 –  Robert Jacobs Dec 19 '13 at 18:18
add comment
df | head -n 1; df | grep ^/dev
share|improve this answer
    
Not bad, but it has the disadvantage that it invokes df twice. –  Keith Thompson Dec 18 '13 at 19:16
1  
Are we short on df invocations? –  ohlemacher Dec 18 '13 at 19:33
    
Not particularly, but there are solutions like terdon's df -h | sed -e 1b -e '/^\/dev/!d' that only invoke df once. The df command can hang in some circumstances; in that case, invoking it just once is probably better. –  Keith Thompson Dec 18 '13 at 19:38
add comment

This should work as well (not tested, though):

df | (read a; echo $a; grep /dev)

or

df | (head -n 1; grep ^/dev)
share|improve this answer
1  
very nice. ^/dev will limit this to lines that start with /dev. Wasn't able to do that as an an edit since I was short 9 characters –  Chaim Geretz Dec 20 '13 at 17:02
add comment
df | grep -n '' | grep -E '^1:|[^:]*:/dev' | sed 's/[^:]*://'

The grep -n inserts line numbers into the stream, we then pull out the first one and the lines of interest via egrep, then remove the added numbers from the output via sed.

You can avoid the sed by using positive lookbehinds (which grep can handle with its PCRE engine (-P)) and -o which tells grep to only print the matched pattern:

df | grep -n '' | grep -Po '(?<=^1:)(.*)|(?<=:)(/dev.*)'
share|improve this answer
add comment

Instead of filtering df output, you can filter its input.

Before:

$ df -h
Filesystem      Size  Used Avail Use% Mounted on
C:/Cygwin/bin   150G   76G   74G  51% /usr/bin
C:/Cygwin/lib   150G   76G   74G  51% /usr/lib
C:/Cygwin       150G   76G   74G  51% /
C:              150G   76G   74G  51% /cygdrive/c

After:

$ mount | grep ^C:/Cygwin | cut -d' ' -f3 | xargs df -h
Filesystem      Size  Used Avail Use% Mounted on
C:/Cygwin/bin   150G   76G   74G  51% /usr/bin
C:/Cygwin/lib   150G   76G   74G  51% /usr/lib
C:/Cygwin       150G   76G   74G  51% /

UPDATE 2014-01-24 08:03 UTC: Only grep for C:/Cygwin in the beginning of a line

share|improve this answer
    
Nice trick but it will not work as expected if you are mounting by UUID instead of device name. The OP wants df style output which means /dev/foo your command will return /dev/disk/by-uuid/ format output unless fstab contains the /dev name. –  terdon Dec 19 '13 at 16:29
    
The mount command uses /etc/mtab, which is updated dynamically, and while I am not sure where df gets its data from, I suspect that on Linux it reads /proc/mounts. Either way I don't understand how fstab is relevant and could not reproduce the problem with UUID-mounted disks. Can you elaborate on it? –  mkalkov Jan 24 at 8:00
add comment

Take the definition of body from sort but keep header line at the top

# print the header (the first line of input)
# and then run the specified command on the body (the rest of the input)
# use it in a pipeline, e.g. ps | body grep somepattern
body() {
    IFS= read -r header
    printf '%s\n' "$header"
    "$@"
}

Use it like this

$ df -h | body grep ^/dev
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda1        23G  6.1G   16G  29% /
/dev/sda6       890G  324G  521G  39% /home
/dev/sdb1       459G  267G  169G  62% /home/user/mnt
share|improve this answer
add comment
df -h | egrep -e Filesystem -e "/dev" -v
share|improve this answer
    
OP has said the heading is locale-dependent, so you can't match it like that. And what is the sda1 doing at the end? –  derobert Dec 20 '13 at 20:06
add comment

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