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?
-
2Is there some particular use-case you have in mind for this, or just generally?– ilkkachuJul 12, 2020 at 20:28
-
1@ilkkachu I want to be able to find it in /abc/.zfs/snapshot/my-snapshot/def/ghi/jkl– unixJul 13, 2020 at 3:22
5 Answers
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
-
-
@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
-
1Bonus points, this works on mac, even when there's weird apfs nonsense going on.– cobbalJul 13, 2020 at 16:18
-
-
@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 hangsdf
. Jul 15, 2020 at 20:22
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
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
-
-
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)– LSerniJul 12, 2020 at 22:54
-
1Is your script doing what
df --output=source /mnt/persistent/test | tail -n1
does?– FreddyJul 13, 2020 at 0:01 -
1@Freddy ...it totally is! I wasn't aware of this particular usage of
df
.– LSerniJul 13, 2020 at 0:05 -
1Instead 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.).– TooTeaJul 13, 2020 at 12:55
If on a GNU system, you could use df
as:
$ df --output=source ~/.bashrc | sed 1d
/dev/sda1
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.