1

I'm writing a bash script and struggling to find a way to create an associative array that holds a key and one attribute to each mounted external hard drive plugged in via USB. My example used here is an associative array, but it does not have to be. Though I feel it makes the most sense. And yes I am using bash 4 for the associative array support.

> /bin/bash --version
GNU bash, version 4.4.12(1)-release (x86_64-apple-darwin16.3.0)

Currently I'm playing around with diskutil list and system_profiler SPUSBDataType as subshells in a for loop. Or just parsing a bunch of the output through pipes with a mixture of sed, grep and awk commands. So far no avail. It should be noted that these apple commands output other things I want to discard such as bluetooth devices and my local hard drive. See below for details.

My desired array would look something like this: myArray=([Name1]=/dev/disk3s2 [Name2]=/dev/disk4s2). I really just need the name and it's mount point. The format of it is flexible. I can parse it later if in a different format. I just need to be able to do a simple for i in "!${myArray[@]}; do echo "Name = ${i}"; echo "mount point = ${myArray[$i]}"; done or something similar.

Note: at the end of the day, its will prompt the user something like "You have N number of external hard drives mounted, please select which one you would like to perform the back up to"

As requested here is example output of the main two commands (diskutil list and system_profiler SPUSBDataType) I have been using in order to try and achieve my goal. Though it should be noted, I don't care if there are other ways to achieve the same desired goal. If you know of other useful commands, please suggest.

> diskutil list
/dev/disk0 (internal, physical):
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:      GUID_partition_scheme                        *500.3 GB   disk0
   1:                        EFI EFI                     209.7 MB   disk0s1
   2:          Apple_CoreStorage Macintosh HD            499.4 GB   disk0s2
   3:                 Apple_Boot Recovery HD             650.0 MB   disk0s3

/dev/disk1 (internal, virtual):
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:                  Apple_HFS Macintosh HD           +499.1 GB   disk1
                                 Logical Volume on disk0s2
                                 A0B29294-0031-40CB-8894-6F56545CCF3C
                                 Unencrypted

/dev/disk3 (external, physical):
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:      GUID_partition_scheme                        *2.0 TB     disk3
   1:                        EFI EFI                     209.7 MB   disk3s1
   2:                  Apple_HFS Storage                 2.0 TB     disk3s2

and

> system_profiler SPUSBDataType
USB:

    USB 3.0 Bus:

      Host Controller Driver: AppleUSBXHCIWPT
      PCI Device ID: 0x9cb1
      PCI Revision ID: 0x0003
      PCI Vendor ID: 0x8086

        BUP Slim SL:

          Product ID: 0xab26
          Vendor ID: 0x0bc2  (Seagate LLC)
          Version: 1.08
          Serial Number: NA96KBJB
          Speed: Up to 5 Gb/sec
          Manufacturer: Seagate
          Location ID: 0x14500000 / 3
          Current Available (mA): 900
          Current Required (mA): 896
          Extra Operating Current (mA): 396
          Media:
            BUP Slim SL:
              Capacity: 2 TB (2,000,398,933,504 bytes)
              Removable Media: No
              BSD Name: disk3
              Logical Unit: 0
              Partition Map Type: GPT (GUID Partition Table)
              USB Interface: 0
              Volumes:
                EFI:
                  Capacity: 209.7 MB (209,715,200 bytes)
                  File System: MS-DOS FAT32
                  BSD Name: disk3s1
                  Content: EFI
                  Volume UUID: 0E239BC6-F960-3107-89CF-1C97F78BB46B
                Storage:
                  Capacity: 2 TB (2,000,054,960,128 bytes)
                  Available: 1.3 TB (1,298,787,659,776 bytes)
                  Writable: Yes
                  File System: Journaled HFS+
                  BSD Name: disk3s2
                  Mount Point: /Volumes/Storage
                  Content: Apple_HFS
                  Volume UUID: E9786DAE-78A7-31B7-B939-8FCCE3C147AB

        Bluetooth USB Host Controller:

          Product ID: 0x8290
          Vendor ID: 0x05ac  (Apple Inc.)
          Version: 1.46
          Speed: Up to 12 Mb/sec
          Manufacturer: Broadcom Corp.
          Location ID: 0x14300000 / 2
          Current Available (mA): 500
          Current Required (mA): 0
          Extra Operating Current (mA): 0
          Built-In: Yes

diskutil list | tail -n +15 will give me basically everything after my local hard drive.

Another thought I had was I could do some sort of for usb in $(system_profiler SPUSBDataType) statement. But I can't figure out the right subshell command to pipe to sed,grep,awk and other tools to parse by blank lines or indentation. More than likely I will not be able to cleanly implement it in one swipe like that.

6
  • Can you add an example output of those commands to the question?
    – Philippos
    Commented Sep 25, 2017 at 11:53
  • 1
    You have upgraded your system's bash to support associative arrays right? (macOS comes with bash v3~)
    – jesse_b
    Commented Sep 25, 2017 at 11:53
  • You say simple array (e.g. indexed) but then give an example of an associative array. Jesse makes a good point about older bash versions not having associative arrays.
    – Jeff Schaller
    Commented Sep 25, 2017 at 12:51
  • @Philippos I added it to the question. I hope that helps. Commented Sep 27, 2017 at 1:51
  • @Jesse_b I did. I also added this point to the question Commented Sep 27, 2017 at 1:51

1 Answer 1

1

I'm not sure if this will work for you or not as it is checking only for external drives and not necessarily USB drives, but I believe it does mostly what you need:

#! /usr/local/bin/bash -
IFS= mapfile -t DISKUTIL_LIST < <(diskutil list external)
declare -A myAssocArray
for line in "${DISKUTIL_LIST[@]}"; do
    DISK_MOUNT=$(echo $line | awk '{print $1}')
    if [[ "${#DISK_MOUNT}" -lt '3' ]]; then
        :
    else
        ARRAY_INDEX=$(mount | grep "$DISK_MOUNT" | awk '{print $3}' | awk -F'/' '{print $NF}')
        MOUNT_POINT=$(mount | grep "$DISK_MOUNT" | awk '{print $1}')
        myAssocArray+=([${ARRAY_INDEX}]="$MOUNT_POINT")
    fi
done
for disk in "${!myAssocArray[@]}"; do
    echo -e "Name:\t\t${disk}\nMount Point:\t${myAssocArray[$disk]}"
done

Sample output for me (I only have one external at the moment):

{0} ➔ ./usb-drives.sh
Name:           JBUTRYN
Mount Point:    /dev/disk2s1
4
  • This looks like it may work. I did not realize you could do diskutil list external. That is a huge help. I will try it as soon as I have some external disks to test with and let you know. I am traveling at the moment and I'm in a lost luggage situation -_- But if you could show me an example of the output that would be helpful. Commented Sep 27, 2017 at 2:01
  • @ByronMansfield . I've updated the original script to produce the type of output you wanted, and included a sample output.
    – jesse_b
    Commented Sep 27, 2017 at 15:16
  • Awesome! I think this is exactly what I'm looking for. Give me some time to try this myself and I'll mark it is answered. Thank you. Commented Sep 28, 2017 at 7:25
  • Confirmed. This is what I was looking for. Thank you for teaching me something new and the ability to use external as an extra argument to diskutil list. Commented Sep 29, 2017 at 2:00

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.