Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I am trying to write a simple script that will iterate through all drives except sda. Right now I have this

for i in $(find /dev/ -name "sd*" ! -name "sda*")
        echo $i

However this includes partitions like /dev/sdb1, whereas I only want the root drive like /dev/sdb.

How do I modify the find statement to guarantee I don't get any of the numbered files?

share|improve this question
Do you really want to exclude sda or is it a wrong example? – andcoz Sep 20 '11 at 15:57
I do want to exclude sda. When the script is finished, basically all the drives in the machine will have all their data erased. I don't want that to happen to sda, as that's where Linux is installed. – Phil Sep 20 '11 at 20:28
up vote 4 down vote accepted

Don't use command substition in that manner, you'll end up with problems when word splitting is applied. Just do

find /dev/ -regex '/dev/sd[a-z]+' ! -name 'sda'

If your true objective is to show base block devices, just look in /sys/block.

share|improve this answer
After some testing, I've found that this won't pick up drives like /dev/sdaa or /dev/sdab – Phil Sep 21 '11 at 13:43
@Phil - Good point, fixed. – Chris Down Sep 21 '11 at 14:11

Supposing you have a single letter after sd, no need to use find.
In bash you can do

shopt -s nullglob
for dev in /dev/sd[!a]; do
    echo "$dev"

The first line is to have no output when no match exist.


To extend to an undetermined number of letters, the glob could be

printf '%s\n' /dev/!(sda|*[0-9])

where !(pattern) means everything but pattern, and excluded patterns are, in the specific case sda and *[0-9] (everything ending in a number).

Extended globs should to be turned on for this to work (i.e. shopt -s extglob).

share|improve this answer
No need to use a for loop, just do shopt -s nullglob ; printf '%s\n' /dev/sd[!a] – Chris Down Sep 20 '11 at 17:01
@Chris Down: I suppose he want to elaborate more on "$dev", echo "$dev" is just a placeholder. – enzotib Sep 20 '11 at 17:13
Why not just ls /dev/sd[!a]? – bahamat Sep 20 '11 at 19:30
Is it possible to do something similar, but supporting more than 26 drives (/dev/sdaa)? – Phil Sep 20 '11 at 20:41
Do you mean printf '%s\n' /dev/sd!(a|*[0-9])? – Phil Sep 20 '11 at 22:24

If you want to get list of disk devices on linux I suggest:

paste -s /sys/dev/block/*/uevent | sed -n '/DEVTYPE=disk/s|.*DEVNAME=\(.*\)\t.*|/dev/\1|p'

This will give you also list of potential disks like /dev/loop3 or /dev/ram12.

If you want list of real "partitonable" disks, you can ask fdisk:

LANG="C" fdisk -l | sed -n 's|^Disk \(/.*/.*\):.*|\1|p'

Then you can filter out the sda:

LANG="C" fdisk -l | sed -n 's|^Disk \(/.*/.*\):.*|\1|p' | grep -v sda
share|improve this answer
I may be a noob, but this looks really complicated and error-prone compared to the alternatives. – Phil Sep 21 '11 at 13:47
Alternatives will fail on many drives. For example hda hdb and other. Also, some drives (not partitions) has numbers in name (loop5, ram3, ...). My solution is fast and reliable. – Michał Šrajer Sep 21 '11 at 17:34

assuming you are sure you are dealing with sd*'s and not hd*'s

find /dev/ -name "sd[b-z]"

should do the trick.

share|improve this answer

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

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