25

If I have a file /abc/def/ghi/jkl, is there a way to tell which device it is located on, or should I parse /etc/mtab and see what matches /abc/def/ghi/jkl better?

2
  • 2
    Is there some particular use-case you have in mind for this, or just generally?
    – ilkkachu
    Jul 12, 2020 at 20:28
  • 1
    @ilkkachu I want to be able to find it in /abc/.zfs/snapshot/my-snapshot/def/ghi/jkl
    – unix
    Jul 13, 2020 at 3:22

5 Answers 5

36

df will tell you device name and mount point, and ls will tell you device numbering:

paul $ pwd
/home/paul/SandBox/Toys/hSort
paul $ ls -l ReadMe
-rw-r--r-- 1 paul paul 296 Jan  8  2020 ReadMe

paul $ df ReadMe
Filesystem     1K-blocks    Used Available Use% Mounted on
/dev/sda9      103818480 3796556  94725184   4% /home

paul $ ls -l /dev/sda9
brw-rw---- 1 root disk 8, 9 Jul 12 12:10 /dev/sda9
6
  • Device file numbers aren't very important nowadays.
    – user253751
    Jul 13, 2020 at 11:43
  • @user253751 Agreed: but a couple of other answers showed more complex methods that found the numbers, so it was a simple extension, in case it mattered. Going direct from the relative filename (even a soft link), to both the device and the mount point, is the joy. Jul 13, 2020 at 12:01
  • 1
    Bonus points, this works on mac, even when there's weird apfs nonsense going on.
    – cobbal
    Jul 13, 2020 at 16:18
  • "df ." note the dot.
    – user62612
    Jul 15, 2020 at 18:12
  • @user62612 The OP specifically asked about a file. . is merely the current directory. A soft-link is followed, unless the target is not mounted. Weirdly, though, a named pipe hangs df. Jul 15, 2020 at 20:22
30

If on Linux, you can run findmnt (manpage) on the path of the file:

findmnt -T /abc/def/ghi/jkl

Since the output is not meant to be parsable, if you want to read the result of a column (in this case SOURCE) into a variable you could do:

source=$(findmnt -rno SOURCE -T /abc/def/ghi/jkl)

(beware $source may not always be the path to a block device file like in the cases of network or fuse file systems, tmpfs, etc.).

1
  • 1
    instead of -T use --target. it is more self documenting. Jul 15, 2020 at 9:56
10

There are several, but it depends on what tools you can use. Are you on a shell, are you writing a script or program? In what language?

The stat() function will return a device identifier for the file specified.

So will the stat(1) command. You could maybe use stat -c %D filename in a script. For example:

stat -c %D /mnt/persistent/test

will give, "0821". That means device 8, minor 33 ("21" is 33 in hex). So I can look into /dev what device has numbers 8, 33:

ls -l /dev | grep " 8, *33 "
brw-rw---- 1 root disk      8,  33 Jun 28 19:08 sdc1

Otherwise, yes, use realpath and match with mtab. In the same example:

REALPATH="$( realpath /mnt/persistent/test )"
df | grep ^/ | tr -s " " \
| while read row; do 
    PREFIX=$( echo "$row" | cut -f 6 -d " " )
    if ( echo "$REALPATH" | grep ^$PREFIX > /dev/null ); then
        echo "$row" | cut -f 1 -d " "
    fi
 done | sort | tail -n 1

Will output:

 /dev/sdc1

Although, as @Freddy pointed out, this whole script comes in a very poor second after df's own syntax:

df --output=source /mnt/persistent/test | tail -n1
5
  • How would someone map the device identifier to a device?
    – roaima
    Jul 12, 2020 at 22:31
  • 1
    @roaima the device identifier is made up of the major and minor device numbers, so on my system for example a file on USB disk /dev/sdc1 has a dev_id of 0821 (major 8, minor 33, that's 21 hex)
    – LSerni
    Jul 12, 2020 at 22:54
  • 1
    Is your script doing what df --output=source /mnt/persistent/test | tail -n1 does?
    – Freddy
    Jul 13, 2020 at 0:01
  • 1
    @Freddy ...it totally is! I wasn't aware of this particular usage of df.
    – LSerni
    Jul 13, 2020 at 0:05
  • 1
    Instead of parsing mtab (which might not even be there or might be out of date), you can also take the major/minor pair from stat() and look the device up under /sys/dev/block/<major>:<minor>. However, note that it only works on Linux and doesn't work for non-device-backed mounts (FUSE, network filesystems, etc.).
    – TooTea
    Jul 13, 2020 at 12:55
5

If on a GNU system, you could use df as:

$ df --output=source ~/.bashrc | sed 1d
/dev/sda1
1

stat is your friend here. The "device" field will tell you what device your file is on. Read this for more info on how to interpret the device field.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .