23

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
    Is there some particular use-case you have in mind for this, or just generally? – ilkkachu Jul 12 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 at 3:22
35

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
| improve this answer | |
  • Device file numbers aren't very important nowadays. – user253751 Jul 13 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. – Paul_Pedant Jul 13 at 12:01
  • 1
    Bonus points, this works on mac, even when there's weird apfs nonsense going on. – cobbal Jul 13 at 16:18
  • "df ." note the dot. – user62612 Jul 15 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. – Paul_Pedant Jul 15 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.).

| improve this answer | |
  • 1
    instead of -T use --target. it is more self documenting. – ctrl-alt-delor Jul 15 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
| improve this answer | |
  • How would someone map the device identifier to a device? – roaima Jul 12 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 at 22:54
  • 1
    Is your script doing what df --output=source /mnt/persistent/test | tail -n1 does? – Freddy Jul 13 at 0:01
  • 1
    @Freddy ...it totally is! I wasn't aware of this particular usage of df. – LSerni Jul 13 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 at 12:55
5

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

$ df --output=source ~/.bashrc | sed 1d
/dev/sda1
| improve this answer | |
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.

| improve this answer | |

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.