3

I need a list of all disk device names (not USB or CD ROM) in the following form DRIVES='sda sdb' so that I can loop through them in a bash script.

Ideal solution would not have to install a special utility and would use /sys|/proc|/dev from the filesystem.

4 Answers 4

3

Recommended solution:

  1. Copy the following python script to a file called internal_block_device_resource:

    #!/usr/bin/env python3
    
    import os
    import re
    from glob import glob
    
    rootdir_pattern = re.compile('^.*?/devices')
    internal_devices = []
    
    def device_state(name):
        """
        Follow pmount policy to determine whether a device is removable or internal.
        """
        with open('/sys/block/%s/device/block/%s/removable' % (name, name)) as f:
            if f.read(1) == '1':
                return
    
        path = rootdir_pattern.sub('', os.readlink('/sys/block/%s' % name))
        hotplug_buses = ("usb", "ieee1394", "mmc", "pcmcia", "firewire")
        for bus in hotplug_buses:
            if os.path.exists('/sys/bus/%s' % bus):
                for device_bus in os.listdir('/sys/bus/%s/devices' % bus):
                    device_link = rootdir_pattern.sub('', os.readlink(
                        '/sys/bus/%s/devices/%s' % (bus, device_bus)))
                    if re.search(device_link, path):
                        return
    
        internal_devices.append(name)
    
    
    for path in glob('/sys/block/*/device'):
        name = re.sub('.*/(.*?)/device', '\g<1>', path)
        device_state(name)
    print(' '.join(internal_devices))
    
  2. Ensure the script has executable permission:

    chmod +x internal_block_device_resource
    
  3. Set your DRIVES bash variable this way:

    DRIVES=$(./internal_block_device_resource)

    $ echo $DRIVES
    sda
    

Initial version:

You need to filter removable devices so you can use this command:

find /sys/block/*/device/block/*/removable -exec bash -c 'echo {} | perl -ne "\$a=\$_;s/^\/sys\/block\/(.*?)\/.*/\$1/;print if (\`cat \$a\` == "0")"' \;

With a USB stick mounted as /dev/sdb, the output is just sda.

5
  • suggestion: use awk with FS / and pick the third field for printing. Will avoid the leaning toothpick syndrome.
    – muru
    Sep 26, 2014 at 8:38
  • @muru: As you said in your answer, the removable special file is not so reliable. I'll try to come up with a better solution. (probably not a oneliner this time) Sep 26, 2014 at 8:47
  • @muru: If you want to give it a try, the new version is ready Sep 26, 2014 at 9:45
  • 1
    Thanks @SylvainPineau, your monster one liner seems to work. Not sure if thats the best or canonical solution but hey it works :-)
    – eskhool
    Sep 27, 2014 at 10:54
  • Your python3 script still works, i had to add an if query: "if os.path.exists('/sys/block/%s/device/block/%s/removable' % (name, name)):" before the "with open.." line, NVMe drives do not have the "removable" file in their device path.
    – mrossi
    Jan 30 at 10:23
1

This works for me:

echo DRIVES=\'`cd /dev; ls sd?; cd`\'

It simply goes into the /dev-directory and outputs everything with sd and one more character. After that, it returns to home.

3
  • Of course, if you wanted to set a variable instead of returning a string containing "DRIVES=", you can simply use DRIVES=`cd /dev; ls sd?; cd`. Sep 26, 2014 at 7:32
  • it will also include usb sticks... (mounted as sdb for example) Sep 26, 2014 at 7:35
  • That's right @JoshuaGleitze, I have tried the obvious but it includes the USB sticks
    – eskhool
    Sep 27, 2014 at 9:18
0

Use lsblk:

$ lsblk -o NAME -nl
sda
sda1
sda2
sda4
sda5
sda6
sdb
sdb1
sdb2
sdb5
sdb6
sr0

This will include anything worth including. You can use the -I option along with the device types to do the filtering.

4
  • it will also include usb sticks and Cdrom... (mounted as sdb/sr0 for example) Sep 26, 2014 at 8:03
  • @SylvainPineau I know. sdb here is an USB stick and sr0 is a CD drive. I'd guess that device types can be filtered.
    – muru
    Sep 26, 2014 at 8:06
  • I think you can use /sys/block/*/device/block/*/removable safely Sep 26, 2014 at 8:07
  • @SylvainPineau No good. Only sr0 was removable.
    – muru
    Sep 26, 2014 at 8:15
0

You can do this with standard linux utilities:

lsblk -n --scsi --output PATH,RM | \
  grep 0 | \
  awk -F ' ' '{print $1}'

lsblk --scsi --output PATH,RM will list all SCSI devices along with the path to them and whether they are removable or not. On my system, it looks like this:

/dev/sda  1
/dev/sdb  0
/dev/sdc  0
/dev/sdd  0
/dev/sde  0

Removable devices will have a 1 in the second column and non-removable devices will have a 0. We filter the list to only those non-removeable devices and output the first field which is the path to the device. This will give you a list like this:

/dev/sdb
/dev/sdc
/dev/sdd
/dev/sde

Saving that in a variable will allow you to loop over the path to each non-removable drive in your system.

$ export DEVICES=$(lsblk -n --scsi --output PATH,RM | grep 0 | awk '{print $1}')
$ for DEVICE in $DEVICES; do echo $DEVICE; done
/dev/sdb
/dev/sdc
/dev/sdd
/dev/sde

You must log in to answer this question.

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