0

To clear things up I have setup folder actions on my mac for whenever a USB device is plugged into my mac it will run a shell script.

When I list all files in the Directory /Volumes i get

$ ls -a
.       ..      .DS_Store   MobileBackups   Storage     WED

What I want to do is list all folders and files located in WED or any USB that pops up, so therefore excluding the directories

.       ..      .DS_Store   MobileBackups   Storage

Leaving me with

WED

What i have for the script so far is:

GLOBIGNORE='/Volumes/MobileBackups*':'/Volumes/Storage*'
find '/Volumes' >> /Users/Brett/dev/USBLOGS/LogUSB.txt

I have tried multiple different ways but it still ends up listing every single file in the /Volumes directory.

Any help would be greatly appreciated. Thanks, Brett

Additionally, it is MAC OS X El Capitan

2
  • Now in the light of day and looking back at what I wrote last night I have modified the code to only use grep once and as now written it can return just the fully qualified pathname(s) of the mounted USB block device(s) from the output of System Profiler in one grep process (per mounded USB block device). I guess I was too tired to see it last night. :) Jan 12, 2016 at 14:30
  • Modified the code once again to handle spaces in the label of the USB block device. Sorry for any confusion with all of this. :) Jan 12, 2016 at 17:55

3 Answers 3

3

Since you only want find to act on USB block devices the following is an example of using information reported by System Profiler to get the Mount Point of any attached and mounted USB block device. By doing it this way it doesn't matter what other mount points exist under /Volumes nor does it matter what the USB block device name is as it's ascertained from System Profiler not the ls command.

I've modified the code, once again, removing the compound command line as it not likely it would be run that way anyway and is easier to maintain in script form while adding the ability to handle spaces in the label name of the USB block device.

By temporarily changing the Internal Field Separator $IFS, adding IFS=$'\n' to the script will ignore the space(s) as a separator in the output of grep when passed to find. So as not to mess with any code in the rest of your script I fist get the state of $IFS and then rest it afterwards.

In a bash script:

#!/bin/bash

_ifs="$IFS"
IFS=$'\n'
for p in $(system_profiler SPUSBDataType | grep -oE '/Volumes/.*$'); do
    if [ -n "$p" ]; then
        find "$p"/*
    fi
done >> filename.txt 
IFS="$_ifs"

The system_profiler SPUSBDataType outputs info on the USB Bus and pipes it through grep to get /Volumes/$whatever e.g. /Volumes/USB Drive using -oE for the '/Volumes/.*$' which outputs /Volumes/ and everything after it to the end of the line, thus '/Volumes/.*$' will translate the fully qualified pathname of the mount point of any mounted USB block devices. So whatever the USB block device is mounted as, it's assigned to $p (I picked "p" for path) and when used with find I added the /* after it so it would not output the dotfiles. The if block is there to avoid any output if no USB block devices are mounted.

4
  • Thank you this was exactly what I needed and is a great explanation as I'm still learning bash. Jan 12, 2016 at 5:56
  • @BrettReinhard, If you need any further explanation just ask. Jan 12, 2016 at 5:59
  • Can you explain to me the declarations before the for statement I'm still iffy with the syntax of things. Jan 12, 2016 at 18:10
  • @BrettReinhard, I wrote a detailed explanation however it would fill 3 separate comments so I don't think I should post that much as comments so first read this from Wikipedia and the $IFS section in Advanced Bash-Scripting Guide: 9.1. Internal Variables for a better understanding of the Internal Field Separator Bash Variable [$IFS]. Then if you don't understand why I wrote it the way I did, I'll see if I can narrow it down to one comment field (600 character max). Jan 12, 2016 at 22:54
1

Here's a variation of user3439894 solution without setting IFS or looping.

system_profiler SPUSBDataType | awk -F": " '/Mount Point/ {printf("%s%c", $2, 0)}' | xargs -0 -IX find X >outfile

Data is parsed from system_profiler with awk. awk prints the mount points terminated with the null character which is then piped to xargs and the results are written to outfile.

To exclude dot files from the output add the option ! -name (not name) and ! -path (not path) to the find command.

system_profiler SPUSBDataType                       |
awk -F": " '/Mount Point/ {printf("%s%c", $2, 0)}'  |
xargs -0 -IX find X ! -name '.*'  ! -path 'X/.*/*' 2>/dev/null >outfile
1
  • I keep telling myself I need to learn awk! :) Base on comments to chazlarson's answer Brett doesn't want the dot-files to show, so can your example be modified easily to exclude them in the output? Anyway, nice answer! +1 Jan 13, 2016 at 1:55
0

My /Volumes dir:

 ➜  /Volumes  ls
BOOTCAMP      Cool Stuff    Macintosh HD  Recovery HD

This command lists only files on the Recovery HD:

➜  /Volumes  find . -type d \( -name BOOTCAMP -o -name Cool\ Stuff \) -prune -o -print
.
./Macintosh HD
./Recovery HD
./Recovery HD/.fseventsd
./Recovery HD/.fseventsd/no_log
./Recovery HD/.metadata_never_index
./Recovery HD/.Trashes
find: ./Recovery HD/.Trashes: Permission denied
./Recovery HD/com.apple.boot.R
./Recovery HD/com.apple.boot.R/Library
...snip...

You can tack more drives onto that list:

\( -name BOOTCAMP -o -name Cool\ Stuff -o -name Foo -o -name Bar -o -name Baz \)

Found here: http://www.theunixschool.com/2012/07/find-command-15-examples-to-exclude.html

4
  • Thank you thank you! I'll play around with this and see how things turn out Jan 12, 2016 at 2:44
  • When adding on more names where does -prune come in, would that be the last one before print? Jan 12, 2016 at 2:59
  • find . -type d ( -name MobileBackups -o -name Storage -o -name .DS_Store -o -name '/*/.' ) -prune -o -print So I have this here and I works perfect except for the fact that within the ./WED drive it shows ./WED/.fsevent and other .something files. I tried to exclude those but it didnt seem to work. Jan 12, 2016 at 3:09
  • find . -type d ( -name Boxcryptor -o -name Bitcasa\ Drive -o -name BOOTCAMP -o -name C -o -name Cloud\ Drive ) -prune -o -print | egrep -i -v -e "\./[A-Za-z0-9].*/\..*" gives me a list without any top-level dot-files.
    – chazlarson
    Jan 12, 2016 at 4:12

You must log in to answer this question.

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