Never been to CodeSnippets before?

Snippets is a public source code repository. Easily build up your personal collection of code snippets, categorize them with tags / keywords, and share them with the world (or not, you can keep them private!)

List mounted volumes on Mac OS X


# See also:
# localvols in
# http://codesnippets.joyent.com/posts/show/1888


/bin/df -l | /usr/bin/sed -E -e 1d -e 's/^([^ ]+[ ]+)[^\/]+//' | /usr/bin/sort -u
/bin/df -l | /usr/bin/sed -E -e 1d -e 's/^([^ ]+[ ]+){5}//' | /usr/bin/sort -u

/bin/df -a | /usr/bin/sed -E -e 1d -e 's/^([^ ]+[ ]+)[^\/]+//' | /usr/bin/sort -u


declare IFS=$'\n'
#for volume in $(/bin/df -l | /usr/bin/sed -E -e 1d -e 's/^([^ ]+[ ]+)[^\/]+//' | /usr/bin/sort -u); do 
for volume in $(/bin/df -a | /usr/bin/sed -E -e 1d -e 's/^([^ ]+[ ]+)[^\/]+//' | /usr/bin/sort -u); do 
   echo "vol: $volume"
done
declare IFS=$' \t\n'



# Cf. Get A List Of Mounted USB Drives
# http://www.adminselfhelp.com/?p=220

system_profiler SPUSBDataType | grep "BSD Name:" | awk '{gsub (" BSD Name: ","");print}'
diskutil info disk1
diskutil info disk1s3

system_profiler SPUSBDataType | sed -E -n 's/ *BSD Name: *([^ ]*)/\1/p'

declare IFS=$'\n'
for device in $(system_profiler SPUSBDataType | sed -E -n 's/ *BSD Name: *([^ ]*)/\1/p'); do
   for usbdevice in $(diskutil info "$device" | sed -E -n 's/ *Mount Point: *(.*)/\1/p' | sed '/^ *$/d'); do
      echo "USB device mounted at: ${usbdevice}"
   done
done
declare IFS=$' \t\n'

Find largest files on Mac OS X


# man mdfind
# find files greater than 50 MB, 100 MB, ...
mdfind 'kMDItemFSSize > 52428800'
mdfind "kMDItemFSSize > $[50*1024*1024]"
mdfind "kMDItemFSSize > $[100*1024*1024]"



# man find

# Note: "find -x ..." (BSD find) or "find -xdev ..." (GNU find)
# Don't descend directories on other filesystems.
# Useful for searching a single hard drive partition and omitting other HDD partitions, /proc, /dev,
# CDROM's, network mounts, etc. (network drives and CD's can be really slow to search)
# see: http://www.softpanorama.org/Tools/find.shtml


df -ah
mount -v

diskutil list
diskutil info /
diskutil info disk0


# compare "Device: ..."
/usr/bin/stat -x /
/usr/bin/stat -x /dev
/usr/bin/stat -x ~

/usr/bin/stat -x /Volumes/*
/usr/bin/stat -x /Volumes/* | sed -E "s/(Device)/$(printf '\e[1m\\1\e[m')/"
/usr/bin/stat -x /Volumes/* | sed -E "s/(Device: [[:digit:]]+,?[[:digit:]]* )/$(printf '\e[1m\\1\e[m')/"
/usr/bin/stat -x /Volumes/* | sed -E "s/(Device: [[:digit:],]+ )/$(printf '\e[1m\\1\e[m')/"


/usr/bin/stat -x / ~ /dev /Volumes /Volumes/* | sed -E "s/(File: .+$|Device: [[:digit:],]+ )/$(printf '\e[1m\\1\e[m')/" | nl
/usr/bin/stat -x / ~ /dev /Volumes /Volumes/* | sed -E -e "s/(File: .+)/$(printf '\e[1m\\1\e[m')/" -e "s/(Device: [[:digit:],]+ )/$(printf '\e[1;31m\\1\e[m')/" | nl


/usr/bin/stat -x /dev/*  | sed -E "s/(File: .+$|Device: [[:digit:],]+ )/$(printf '\e[1m\\1\e[m')/" | nl
/usr/bin/stat -x /dev/* | sed -E -e "s/(File: .+)/$(printf '\e[1m\\1\e[m')/" -e "s/(Device: [[:digit:],]+ )/$(printf '\e[1;31m\\1\e[m')/" | nl


/usr/bin/find /dev | nl
/usr/bin/find /dev -not -type d | nl
/usr/bin/find -x /dev -not -type d | nl
/usr/bin/find -x /dev -not -type d -ls | nl



# find the 10 largest files on your system (> 50 MB)
/usr/bin/sudo -H -i

# only skip /dev
/usr/bin/find / -not \( -type d -path '/dev' -prune \) -type f -size +$[50*1024*1024]c -ls 2>/dev/null | /usr/bin/sort -rn -k 7,7 | /usr/bin/head | /usr/bin/nl

# do not descend into directories mounted from other filesystems (including network-mounted filesystems)
/usr/bin/find -x / -type f -size +$[50*1024*1024]c -ls 2>/dev/null | /usr/bin/sort -rn -k 7,7 | /usr/bin/head | /usr/bin/nl

exit



# list local mounted volumes (file systems) including hard drive disk partitions, CDs, iPods, etc
/bin/df -l | /usr/bin/sed -E -e 1d -e 's/^([^ ]+[ ]+)[^\/]+//' | /usr/bin/sort -u

# list local hard drive disk partitions only (/dev/disk0*)
/bin/df -l | /usr/bin/sed -E -e 1d -e '/^\/dev\/disk0/!d' -e 's/^([^ ]+[ ]+)[^\/]+//' | /usr/bin/sort -u


# only scan local hard drive disk partitions (one by one)
/usr/bin/sudo -H -i
declare IFS=$'\n'
for volume in $(/bin/df -l | /usr/bin/sed -E -e 1d -e '/^\/dev\/disk0/!d' -e 's/^([^ ]+[ ]+)[^\/]+//' | /usr/bin/sort -u); do 
   echo 
   echo "... scanning volume: ${volume}"
   /usr/bin/find -x "${volume}" -type f -size +$[50*1024*1024]c -ls 2>/dev/null | /usr/bin/sort -rn -k 7,7 | /usr/bin/head | /usr/bin/nl
done
declare IFS=$' \t\n'
exit



# store file paths of files > 50 MB in array  (only skip /dev)

/usr/bin/sudo -H -i
man ruby | less -p 777 
IFS=$'\777' 
#array=( $(/usr/bin/find / -not \( -type d -path '/dev' -prune \) -type f -size +$[50*1024*1024]c -exec printf "%s\777" '{}' \; 2>/dev/null) ) 
array=( $(/usr/bin/find / -not \( -type d -path '/dev' -prune \) -type f -size +$[50*1024*1024]c -exec printf "%s\777" '{}' + 2>/dev/null) ) 
IFS=$' \t\n'
echo ${#array[@]} 
printf "%s\n" "${array[@]}" | nl 
echo "${array[0]}" 
exit



# store all file paths of files > 50 MB on local hard drive in array  (only scan local hard drive partitions)

/usr/bin/sudo -H -i

declare -a array tmparray
declare IFS=$'\n'

for volume in $(/bin/df -l | /usr/bin/sed -E -e 1d -e '/^\/dev\/disk0/!d' -e 's/^([^ ]+[ ]+)[^\/]+//' | /usr/bin/sort -u); do 
   echo 
   echo "... scanning volume: ${volume}"

   IFS=$'\777' 
   #tmparray=( $(/usr/bin/find -x "${volume}" -type f -size +$[50*1024*1024]c -exec printf "%s\777" '{}' \; 2>/dev/null) ) 
   #tmparray=( $(/opt/local/bin/gfind "${volume}" -xdev -type f -size +$[50*1024*1024]c -exec printf "%s\777" '{}' + 2>/dev/null) ) 
   tmparray=( $(/usr/bin/find -x "${volume}" -type f -size +$[50*1024*1024]c -exec printf "%s\777" '{}' + 2>/dev/null) ) 
   array=( "${array[@]}" "${tmparray[@]}" )
   unset -v tmparray
   declare -a tmparray
   IFS=$'\n'
done


# this will truncate file paths containing spaces
printf "%s\000" "${array[@]}" | xargs -0 /usr/bin/stat -f $'%z\t\t%N' | sort -rn | awk '{print $1/(1024*1024.0),$2;}'


# this will truncate file paths containing newlines \n
printf "%s\000" "${array[@]}" | xargs -0 /usr/bin/stat -f $'%z\t\t%N' | sort -rn -k 1,1 -t $'\t' | \
      awk -F $'\t' '{printf "MB:  %-20s", $1/(1024*1024.0); for (i=2;i<NF+1;i++) {printf "%s",$i}; print ""}'


# encode newlines \n as NEWLINE
# cf. Sorting arrays in Bash, http://codesnippets.joyent.com/posts/show/1592
printf "%s\000\n" "${array[@]}" | sed -e :a -e '$!N; s/\n/NEWLINE/g; ta' | ruby -n -e 'p $_.to_s'
printf "%s\000\n" "${array[@]}" | sed -e :a -e '$!N; s/\n/NEWLINE/g; ta' | tr '\000' '\n' | ruby -n -e 'p $_.to_s'
printf "%s\000\n" "${array[@]}" | sed -e :a -e '$!N; s/\n/NEWLINE/g; ta' | tr '\000' '\n' | sed -e 's/^NEWLINE//' | ruby -n -e 'p $_.to_s'

printf "%s\000\n" "${array[@]}" | sed -e :a -e '$!N; s/\n/NEWLINE/g; ta' | tr '\000' '\n' | sed -e 's/^NEWLINE//' -e s/NEWLINE/$'\\\n'/ | ruby -n -e 'p $_.to_s'


# In the first two commands (printf, stat) use \000 and \777 to mark the end of each file path, then ... :
# - encode embedded newlines \n as NEWLINE (sed)
# - convert \777 into \n again (tr)
# - delete the last line (sed)
# - sort the resulting lines according to the first column of bytes (sort)
# - use awk to add line numbers and convert bytes into megabytes (awk)
# - and finally restore embedded newline characters in file paths (sed)

printf "%s\000" "${array[@]}" | xargs -0 /usr/bin/stat -n -f $'%z\t\t%N\777' | /usr/bin/sed -e :a -e '$!N; s/\n/NEWLINE/g; ta' | tr $'\777' $'\n' | sed '$d' | \
sort -rn -k 1,1 -t $'\t' | awk -F "\t" '{printf "%s\t%-20s", NR, $1/(1024*1024.0); for (i=2;i<NF+1;i++) {printf "%s",$i}; print ""}' | sed -e $'s/NEWLINE/\\\n/'


# same as previous command sequence except that the awk command (cf. ORS) marks the end of each file path with \777 again

printf "%s\000" "${array[@]}" | xargs -0 /usr/bin/stat -n -f $'%z\t\t%N\777' | /usr/bin/sed -e :a -e '$!N; s/\n/NEWLINE/g; ta' | tr $'\777' $'\n' | sed '$d' | \
sort -rn -k 1,1 -t $'\t' | awk -F "\t" -v ORS="\777" '{printf "%-20s", $1/(1024*1024.0); for (i=2;i<NF+1;i++) {printf "%s",$i}; print ""}' | sed -e $'s/NEWLINE/\\\n/'


# use the previous command sequence to read the sorted list of file paths into an array again

IFS=$'\777' 

result=( 
$(
printf "%s\000" "${array[@]}" | xargs -0 /usr/bin/stat -n -f $'%z\t\t%N\777' | /usr/bin/sed -e :a -e '$!N; s/\n/NEWLINE/g; ta' | tr $'\777' $'\n' | sed '$d' | \
sort -rn -k 1,1 -t $'\t' | awk -F "\t" -v ORS="\777" '{printf "%-20s", $1/(1024*1024.0); for (i=2;i<NF+1;i++) {printf "%s",$i}; print ""}' | sed -e $'s/NEWLINE/\\\n/'
)
)

IFS=$'\n'


# print sorted list of file sizes (in MB) with file paths
for ((i=0; i < ${#result[@]}; i++)); do printf "%-5s %s\n" "$[i+1]" "${result[${i}]}"; done


exit   # sudo shell




#----------------------------------------------------------------------------------------------------




# ... testing weird file paths
mkfile 10m ${HOME}/Desktop/'te:st\file:'

# convert file sizes to megabyte with awk (> 1 MB)
/usr/bin/find -x ~/Desktop -type f -size +$[1*1024*1024]c -print0 2>/dev/null | xargs -0 stat -f "%z:  %N" | \
      sort -rn | awk -F: '{printf "%-20s", $1/(1024*1024.0); for (i=2;i<NF+1;i++) {printf "%s%s",$i,(i==NF) ? "\n" : ":"}}'


# find the 10 largest directories in the current directory
/usr/bin/find -x . -mindepth 1 -maxdepth 1 -type d -print0 | xargs -0 du -hs
/usr/bin/find -x . -mindepth 1 -maxdepth 1 -type d -print0 | xargs -0 du -ks | sort -rn | head

# awk: print the first field and from the second field to the end (just in case there are file paths with spaces)
/usr/bin/find -x . -mindepth 1 -maxdepth 1 -type d -print0 | xargs -0 du -ks | sort -rn | head | \
    awk -F' ' '{printf "%-20s", $1/1024.0; for (i=2;i<NF+1;i++) {printf "%s ",$i}; print ""}'




#----------------------------------------------------------------------------------------------------




# sort file sizes & file paths containing newlines \n
# cf. Sorting arrays in Bash, http://codesnippets.joyent.com/posts/show/1592

mkfile 10m ${HOME}/Desktop/'te:st\file'.txt
mkfile 10m ${HOME}/Desktop/'te:st\file:'
mkfile 10m ${HOME}/Desktop/$'te:s\nt\\file:'


declare -a file_path_array

man ruby | less -p '777'

IFS=$'\777'
file_path_array=($(/usr/bin/find -x ~/Desktop -type f -size +$[1*1024*1024]c -print0 2>/dev/null | xargs -0 -n 500 printf "%s\777"))
IFS=$' \t\n'


echo "${#file_path_array[@]}"
echo "${file_path_array[@]}"
printf "%s\n" "${file_path_array[@]}"  | ruby -n -e 'p $_.to_s'


declare -a file_path_array2
for ((i=0; i < "${#file_path_array[@]}"; i++)); do 
   mbyte=$(/usr/bin/stat -f "%z" "${file_path_array[$i]}" | awk '{print $1/(1024*1024.0);}')
   file_path_array2[${i}]="${mbyte}: ${file_path_array[$i]}"
done

echo "${#file_path_array2[@]}"
echo "${file_path_array2[@]}"



IFS=$'\n'

declare -a file_path_array2_sorted
file_path_array2_sorted=( $(printf "%s\000\n" "${file_path_array2[@]}" | sed -e :a -e '$!N; s/\n/NEWLINE/g; ta' | tr '\000' '\n' | \
      sed -e 's/^NEWLINE//' | sort -rn -t . -k 1,1 -k 2,2) )

IFS=$' \t\n'

for ((i=0; i < "${#file_path_array2_sorted[@]}"; i++)); do printf "%s\n" "${file_path_array2_sorted[$i]//NEWLINE/$'\n'}"; done | nl
for ((i=0; i < "${#file_path_array2_sorted[@]}"; i++)); do printf "%s\n" "${file_path_array2_sorted[$i]//NEWLINE/\n}"; done | nl
for ((i=0; i < "${#file_path_array2_sorted[@]}"; i++)); do 
   printf "%s" "${file_path_array2_sorted[$i]//NEWLINE/\n}" | ruby -0777 -n -e 'p $_.to_s'
done | nl



#----------------------------------------------------------------------------------------------------



# alternative

declare -i i=0
declare -a file_path_array


while read -d $'\000' filepath; do 
   mbyte=$(/usr/bin/stat -f "%z" "${filepath}" | awk '{print $1/(1024*1024.0);}') 
   file_path_array[${i}]="${mbyte}:   ${filepath}"
   let i++
done < <(/usr/bin/find -x ~/Desktop -type f -size +$[1*1024*1024]c -print0 2>/dev/null | sed -E '/\\/s/\\/\\\\/g')


IFS=$'\n'

declare -a file_path_array_sorted
file_path_array_sorted=( $(printf "%s\000\n" "${file_path_array[@]}" | sed -e :a -e '$!N; s/\n/NEWLINE/g; ta' | tr '\000' '\n' | \
      sed -e 's/^NEWLINE//' | sort -rn -t . -k 1,1 -k 2,2) )

IFS=$' \t\n'


for ((i=0; i < "${#file_path_array_sorted[@]}"; i++)); do printf "%s\n" "${file_path_array_sorted[$i]//NEWLINE/$'\n'}"; done | nl
for ((i=0; i < "${#file_path_array_sorted[@]}"; i++)); do printf "%s\n" "${file_path_array_sorted[$i]//NEWLINE/\n}"; done | nl
for ((i=0; i < "${#file_path_array_sorted[@]}"; i++)); do 
   printf "%s" "${file_path_array_sorted[$i]//NEWLINE/\n}" | ruby -0777 -n -e 'p $_.to_s' 
done | nl



#----------------------------------------------------------------------------------------------------



# same for directory paths containing possible newlines \n

declare -i i=0
declare -a dir_path_array

while read -d $'\000' dirpath; do 
   dir_size=$(/usr/bin/du -ks "${dirpath}" | /usr/bin/awk '/^[[:digit:]]+/{print $1/1024.0}') 
   dir_path_array[${i}]="${dir_size}     ${dirpath}"
   let i++
done < <(/usr/bin/find -x . -mindepth 1 -maxdepth 1 -type d -print0 2>/dev/null | sed -E '/\\/s/\\/\\\\/g')

echo "${#dir_path_array[@]}"
echo "${dir_path_array[@]}"
printf "%s\n" "${dir_path_array[@]}"  | ruby -n -e 'p $_.to_s'


IFS=$'\n'

declare -a dir_path_array_sorted
dir_path_array_sorted=( $(printf "%s\000\n" "${dir_path_array[@]}" | sed -e :a -e '$!N; s/\n/NEWLINE/g; ta' | tr '\000' '\n' | \
      sed -e 's/^NEWLINE//' | sort -rn -t . -k 1,1 -k 2,2) )

IFS=$' \t\n'


for ((i=0; i < "${#dir_path_array_sorted[@]}"; i++)); do printf "%s\n" "${dir_path_array_sorted[$i]//NEWLINE/$'\n'}"; done | nl
for ((i=0; i < "${#dir_path_array_sorted[@]}"; i++)); do printf "%s\n" "${dir_path_array_sorted[$i]//NEWLINE/\n}"; done | nl
for ((i=0; i < "${#dir_path_array_sorted[@]}"; i++)); do 
   printf "%s" "${dir_path_array_sorted[$i]//NEWLINE/\n}" | ruby -0777 -n -e 'p $_.to_s' 
done | nl



#----------------------------------------------------------------------------------------------------



# get file sizes via ls command
ls -alS
ls -alSr

ls -ahlS
ls -ahlSr

ls -alSrR



#----------------------------------------------------------------------------------------------------




# bigfiles (see below)
# scan local hard disk (/dev/disk0*)

IFS=$'\n'
bigfiles -v -m 10 $(/bin/df -l | /usr/bin/sed -E -e 1d -e '/^\/dev\/disk0/!d' -e 's/^([^ ]+[ ]+)[^\/]+//' | /usr/bin/sort -u)
IFS=$' \t\n'


IFS=$'\777'
bigfiles $(localvols -7)  # localvols (see below)
IFS=$' \t\n'



bigfiles.c:
/*
*
* bigfiles -- list big files in given directories
*
* License: The MIT License, http://www.opensource.org/licenses/mit-license.php
* Copyright (c) 2009 jv
*
* compile with: gcc -std=c99 -Wall -Wextra -pedantic -O3 -o bigfiles bigfiles.c
*
* For how to implement recursive directory scanning please see:
* "fts(3) or Avoiding to Reinvent the Wheel",
* http://keramida.wordpress.com/2009/07/05/fts3-or-avoiding-to-reinvent-the-wheel/
*
*
* man 2 stat: 
*
* struct stat {
*   ...
*   off_t    st_size;   // file size, in bytes
*   ...
* }
*
*
* egrep -Irs --color 'typedef.*[[:space:]]off_t([[:space:];]|$)' /usr/include
* egrep -Irs --color 'typedef.*[[:space:]]__darwin_off_t([[:space:];]|$)' /usr/include
* egrep -Irs --color 'typedef.*[[:space:]]__int64_t([[:space:];]|$)' /usr/include
*
* typedef __darwin_off_t         off_t;
* typedef __int64_t	__darwin_off_t;		// [???] Used for file sizes
* typedef long long            __int64_t;
*
*
*  
* usage example to scan local hard disk:
* IFS=$'\n'
* ~/Desktop/bigfiles -v -m 10 $(/bin/df -l | /usr/bin/sed -E -e 1d -e '/^\/dev\/disk0/!d' -e 's/^([^ ]+[ ]+)[^\/]+//' | /usr/bin/sort -u)
* IFS=$' \t\n'
*
*
*/


#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fts.h>
#include <unistd.h>      // getopt
#include <limits.h>      // PATH_MAX


#define MAX_FILEPATH_LENGTH     2 * PATH_MAX     // 2048 (in 2009)	
#define STRUCTS_IN_ARRAY        15000


static int      ptree(char * const argv[], int argc, int megabytes, unsigned long long int print, int printfid, int verbose);

static void usage()
{

   static char const *usageinfo[] = { 
      "bigfiles -- list big files in given directories", 
      "Usage:", 
      "bigfiles [-0] [-7] [-hv] [-m mbytes] [-n num] [ [dir1] [dir2] ...]",
      "-0: print each item to stdout in the following format:  size\\777path\\777\\000",
      "-7: print each item to stdout in the following format:  size\\777path\\777",
      "-h: help",
      "-m: megabytes (default: 50, min size: 2)",
      "-n: print n items (file size in MB & file path; default: 20)",
      "-n 0: print all items",
      "-v: verbose",
      "Note:",
      "- Files named '.' or '..' get scanned.",
      "- File search will not descend into directories that have a different device number than the file from which the descent began.",
      "- fts_options: FTS_COMFOLLOW | FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV | FTS_SEEDOT  (see man 3 fts)"
   };

   fprintf(stderr, "\n%s\n\n%s\n\n\t%s\n\n\t%s\n\n\t%s\n\n\t%s\n\n\t%s\n\n\t%s\n\n\t%s\n\n\t%s\n\n%s\n\n\t%s\n\n\t%s\n\n\t%s\n\n", 
      usageinfo[0], usageinfo[1], usageinfo[2], usageinfo[3], usageinfo[4], 
      usageinfo[5], usageinfo[6], usageinfo[7], usageinfo[8], usageinfo[9], 
      usageinfo[10], usageinfo[11], usageinfo[12], usageinfo[13]
   );

}




int main(int argc, char * const argv[])
{

   int megabytes = 50;
   unsigned long long int print = 20;

   int verbose = 0;
   int printfid = 10;   // defaults to newline character \n; cf. man ascii (decimal set)

   if ( argc == 1 ) { usage(); return 0; }

   int ch;

   while ((ch = getopt(argc, (char **)argv, "m:n:07hv")) != -1) 
   {
      switch (ch)
      {
         case '0':
            printfid = 0;
            break;
         case '7':
            printfid = 7;
            break;
         case 'h':
            usage();
            return 0;
         case 'm':
            megabytes = atoi(optarg);
            break;
         case 'n':
            print = atoi(optarg);
            break;
         case 'v':
            verbose = 1;
            break;
         case '?':
            default:
            usage();
            return 1;
      }
   }

   argc -= optind;
   argv += optind;

   if ( megabytes < 2 )
      megabytes = 2;

   int rc;

   if ((rc = ptree(argv, argc, megabytes, print, printfid, verbose)) != 0) 
      rc = 1;

   return rc;

}


void copystr (char *srcstr, char *tgtstr)
{
   while ( *srcstr ) { *tgtstr++ = *srcstr++; }
   *tgtstr = '\0';
}


struct file_size_path
{ 
    unsigned long long int file_size;
    char *file_path;
};


// VLA (variable length array) in C99
// For some VLA links see: Xcode now defaults to use C99 - so what's C99?,
// http://www.cocoabuilder.com/archive/message/xcode/2008/5/30/21989

struct file_size_path array_file_size_path[STRUCTS_IN_ARRAY];  


// qsort / mergesort struct comparison function (file_size field)
int struct_cmp_by_filesize(const void *a, const void *b)
{

   struct file_size_path *ia = (struct file_size_path *)a;
   struct file_size_path *ib = (struct file_size_path *)b;

   // return 1 or -1 if file_size members are not equal
   //if (ia->file_size > ib->file_size) return 1;
   //if (ia->file_size < ib->file_size) return -1;

   if (ia->file_size < ib->file_size) return 1;
   if (ia->file_size > ib->file_size) return -1;

   // return 0 if file_size members are equal
   return 0;
 
} 


// struct array printing function
void print_struct_array(struct file_size_path *array, unsigned long long int nitems, int printfid)
{

   unsigned long long int i;
 
   for(i=0; i < nitems; i++)
   {

      switch (printfid)
      {

         case 0:
                printf("%llu\777%s\777", array[i].file_size, array[i].file_path);
                putchar(0);
                break;
         case 7:
                printf("%llu\777%s\777", array[i].file_size, array[i].file_path);
                break;
         case 10:
                printf("%-12llu %s\n", array[i].file_size, array[i].file_path);
                break;
         default:
                break;

      }


   }

}


static int ptree(char * const argv[], int argc, int megabytes, unsigned long long int print, int printfid, int verbose)
{

   int i = 0;
   unsigned long long int x = 0;

   long long int bytes = megabytes * 1024 * 1024;

   unsigned long long int print_n_items = print;

   void copystr (char *srcstr, char *tgtstr);

   char filepathstr[MAX_FILEPATH_LENGTH];

   unsigned long long int file_count = 0;
   unsigned long long int array_index = 0;
   unsigned long long int number_of_array_items = 0;

   FTS *ftsp;
   FTSENT *p, *chp;
   //int fts_options = FTS_COMFOLLOW | FTS_LOGICAL | FTS_NOCHDIR | FTS_SEEDOT;
   //int fts_options = FTS_COMFOLLOW | FTS_LOGICAL | FTS_NOCHDIR | FTS_XDEV | FTS_SEEDOT;
   int fts_options = FTS_COMFOLLOW | FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV | FTS_SEEDOT;
   int rval;
   rval = 0;

   if ((ftsp = fts_open(argv, fts_options, NULL)) == NULL) 
   {
      warn("fts_open");
      return -1;
   }


   // Initialize ftsp with as many argv[] parts as possible.
   chp = fts_children(ftsp, 0);

   //if (chp == NULL) return 0;      // no files to traverse

   if (chp == NULL)
   {
      fprintf(stderr, "No files to traverKKKse. See -h option. Exiting ...\n");
      return 1;
   }


   while ((p = fts_read(ftsp)) != NULL) 
   {

      switch (p->fts_info) 
      { 
  

/*

         // cf. man 3 fts

         case FTS_DNR:
                    //printf("directory which cannot be read: %s\n", p->fts_path);
                    break;

         case FTS_DC:
                    //printf("directory that causes a cycle in the tree: %s\n", p->fts_path);
                    break;

         case FTS_D:
                    //printf("directory: %s\n", p->fts_path);
                    break;

         case FTS_SLNONE:
                    //printf("symbolic link with a non-existent target: %s\n", p->fts_path);
                    break;

         case FTS_SL:
                    //printf("symbolic link: %s\n", p->fts_path);
                    break;

*/


         case FTS_F:

                    file_count++;

                    if ( p->fts_statp->st_size < bytes ) break;   // ignore files < bytes

                    // convert bytes to megabytes
                    array_file_size_path[array_index].file_size = p->fts_statp->st_size / (1024*1024); 

                    //printf("path: %s\n", p->fts_path);
                    //printf("size: %jd\n", (intmax_t)p->fts_statp->st_size);
  
                    copystr(p->fts_path, filepathstr);

                    array_file_size_path[array_index].file_path = calloc( strlen(filepathstr) + 1, sizeof(char) );

                    if (array_file_size_path[array_index].file_path == NULL) exit(1);

                    strcpy(array_file_size_path[array_index].file_path, filepathstr);

                    array_index++;  // we will increment array_index one too many here in the last while loop

                    break;

         default:
                    break;

      }   // switch

   }   // while


   fts_close(ftsp);


   if (array_index == 0)
   {

      printf("\nNo files found.\nSee -h option to modify search parameters.\n\n");

      if (verbose == 1)
      {

         printf("\nSearching for files larger than:  %i  MB\n", megabytes);
         printf("\nPrint  %llu  sorted items (file size in MB & file path).\n", print_n_items);
         printf("\nNumber of files scanned:  %llu\n", file_count);
         printf("\nNumber of files found:  %llu\n", array_index);
         printf("\nDirectories scanned:\n\n");

         for(i=0; i < argc; i++)
         {
            printf("%i: %s\n", i+1, argv[i]);
         }

         printf("\n\n\n");

      }

      return 0;
   }


   number_of_array_items = array_index;

   array_index = number_of_array_items - 1;

   size_t structs_len = number_of_array_items;
   //size_t structs_len = sizeof(array_file_size_path) / sizeof(struct file_size_path);

   // sort array using qsort functions
   //qsort(array_file_size_path, structs_len, sizeof(struct file_size_path), struct_cmp_by_filesize);
   mergesort(array_file_size_path, structs_len, sizeof(struct file_size_path), struct_cmp_by_filesize);


   if ( (print_n_items == 0) || (print_n_items > number_of_array_items) )
      print_n_items = number_of_array_items;


   if (verbose == 1)
   {

      printf("\nSearching for files larger than:  %i  MB\n", megabytes);
      printf("\nPrint  %llu  sorted items (file size in MB & file path).\n", print_n_items);
      printf("\nNumber of files scanned:  %llu\n", file_count);
      printf("\nNumber of files found:  %llu\n", number_of_array_items);
      printf("\nDirectories scanned:\n\n");

      for(i=0; i < argc; i++)
      {
         printf("%i: %s\n", i+1, argv[i]);
      }

      printf("\n\n\n");

   }


   // print sorted struct array
   print_struct_array(array_file_size_path, print_n_items, printfid);


   // free memory
   for( x=0; x < number_of_array_items; x++ )
   {

      //memset(array_file_size_path[x].file_path, 0, sizeof(array_file_size_path[x].file_path));
      //memset(array_file_size_path[x].file_path, 0, strlen(array_file_size_path[x].file_path) + 1);

      bzero(array_file_size_path[x].file_path, sizeof(array_file_size_path[x].file_path));

      free (array_file_size_path[x].file_path);
   }


   return 0;

}  // ptree



localvols.c:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/param.h>
#include <sys/ucred.h>
#include <sys/mount.h>
#include <errno.h>
#include <unistd.h>      // getopt


// localvols - list local hfs & ufs volumes (file systems) on Mac OS X

//  License: The MIT License, http://www.opensource.org/licenses/mit-license.php
//  Copyright (c) 2009 jv

// compile with: gcc -Wall -O3 -o localvols  localvols.c


static void usage()
{

   static char const *usageinfo[] = { 

      "localvols -- list locally mounted hfs & ufs volumes (file systems) on Mac OS X",
 
      "Usage:", 
      "localvols [-0] [-7] [-afhu]",
      "-0: print volume paths to stdout in the following format:  vol1\\000vol2\\000vol3\\000 (-print0)",
      "-7: print volume paths to stdout in the following format:  vol1\\777vol2\\777vol3\\777 (-print7)",
      "-a: list all locally mounted hfs & ufs file systems",
      "-f: list all locally mounted hfs file systems only",
      "-h: help",
      "-u: list all locally mounted ufs file systems only",

      "Note:",
      "- file systems: hfs, ufs",
      "- default: list the local hard drive disk partitions mounted on /Volumes/*",

      "Examples:",

      "localvols",

      "localvols -7 | ruby -0777 -n -e 'p $_.to_s'",

      "IFS=$'\\777'",
      "lvols=( $(localvols) )",
      "IFS=$' \\t\\n'",
      "echo \"${lvols[0]}\"",
      "echo \"${lvols[1]}\"",
      "echo \"${lvols[@]}\"",

      "IFS=$'\\777'", 
      "bigfiles $(localvols -7)", 
      "IFS=$' \\t\\n'"

   };


   fprintf(stderr, "\n%s\n\n%s\n\n\t%s\n\n\t%s\n\n\t%s\n\n\t%s\n\n\t%s\n\n\t%s\n\n\t%s\n\n\n%s\n\n\t%s\n\n\t%s\n\n\
      \n%s\n\n\t%s\n\n\t%s\n\n\t%s\n\t%s\n\t%s\n\t%s\n\t%s\n\t%s\n\n\t%s\n\t%s\n\t%s\n\n", 
      usageinfo[0], usageinfo[1], usageinfo[2], usageinfo[3], usageinfo[4], 
      usageinfo[5], usageinfo[6], usageinfo[7], usageinfo[8], usageinfo[9], 
      usageinfo[10], usageinfo[11], usageinfo[12], usageinfo[13], usageinfo[14], 
      usageinfo[15], usageinfo[16], usageinfo[17], usageinfo[18], usageinfo[19], 
      usageinfo[20], usageinfo[21], usageinfo[22], usageinfo[23]
   );

}


void printfid_function(int printfid, const char * volpath)
{

   switch (printfid)
   {

     case 0:
            printf("%s", volpath);
            putchar(0);
            break;
     case 7:
            //printf("%s\777", volpath);
            printf("%s", volpath);
            putchar('\777');
            break;
     case 10:
            printf("%s\n", volpath);
            break;
     default:
            break;

   }

}


int main(int argc, const char **argv)
{
   struct statfs *mountlist;
   int ch, n, i;

   int all = 0;
   int all_hfs = 0;
   int all_ufs = 0;
   int printfid = 10;   // defaults to newline character \n; cf. man ascii (decimal set)

   while ((ch = getopt(argc, (char **)argv, "07afhu")) != -1) 
   {
      switch (ch)
      {
         case '0':
            printfid = 0;
            break;
         case '7':
            printfid = 7;
            break;
         case 'a':
            all = 1;
            break;
         case 'f':
            all_hfs = 1;
            break;
         case 'h':
            usage();
            return 0;
         case 'u':
            all_ufs = 1;
            break;
         case '?':
            default:
            usage();
            return 1;
      }
   }

   argc -= optind;
   argv += optind;

   if (argc > 0) { usage(); return 1; }

   //n = getmntinfo(&mountlist, 0);
   //n = getmntinfo(&mountlist, MNT_NOWAIT);
   n = getmntinfo(&mountlist, MNT_WAIT);     //  see man 3 getmntinfo and man 2 getfsstat

   if (n < 0) 
   {
      fprintf(stderr, "getmntinfo failed: %s\n", strerror(errno));
      exit(1);
   }


   if (all == 1) 
   {
      for(i=0; i<n; i++) 
      {

         if ( ( (mountlist[i].f_flags & MNT_LOCAL) == MNT_LOCAL ) &&
              ( (strcmp(mountlist[i].f_fstypename, "hfs") == 0) || (strcmp(mountlist[i].f_fstypename, "ufs") == 0) )
            )
         {

            printfid_function(printfid, mountlist[i].f_mntonname);
         }

      }

      return 0;

   }


   if (all_hfs == 1) 
   {

      for(i=0; i<n; i++) 
      {

         if ( ((mountlist[i].f_flags & MNT_LOCAL) == MNT_LOCAL ) && (strcmp(mountlist[i].f_fstypename, "hfs") == 0) )
         {
            printfid_function(printfid, mountlist[i].f_mntonname);
         }

      }

      return 0;

   }


   if (all_ufs == 1) 
   {

      for(i=0; i<n; i++) 
      {

         if ( ((mountlist[i].f_flags & MNT_LOCAL) == MNT_LOCAL ) && (strcmp(mountlist[i].f_fstypename, "ufs") == 0) )
         {
            printfid_function(printfid, mountlist[i].f_mntonname);
         }

      }

      return 0;

   }


   // default

   // get the device node entry (/dev/disk*, 10 characters) of the root path /
   // see: man 8 diskutil | less -p DEVICES

   char root_path_device_node[11];   // can store up to 11 chars; the last index: 10  is used for the terminating '\0' char below

   //printf("%s\n", root_path_device_node);
   //printf("sizeof(root_path_device_node): %zu\n", sizeof(root_path_device_node));

   for(i=0; i<n; i++) 
   {

      if ( (strcmp(mountlist[i].f_mntonname, "/") == 0) )
      {
         strncpy(root_path_device_node, mountlist[i].f_mntfromname, 10);
         root_path_device_node[10] = '\0';
         break;
      }

   }


   for(i=0; i<n; i++) 
   {
      if ( 
            ( (mountlist[i].f_flags & MNT_LOCAL) == MNT_LOCAL ) &&
            ( (strcmp(mountlist[i].f_fstypename, "hfs") == 0) || (strcmp(mountlist[i].f_fstypename, "ufs") == 0) ) && 
              (strncmp(mountlist[i].f_mntfromname, root_path_device_node, 10) == 0) &&
            ( (strcmp(mountlist[i].f_mntonname, "/") == 0) || (strncmp(mountlist[i].f_mntonname, "/Volumes/", 9) == 0) ) 
         )
      {
         printfid_function(printfid, mountlist[i].f_mntonname);
      }   // if

   }   // for


   return 0;

}



Mergesort

Mergesort implemented in Ruby. Because of it's performance not really suitable for productive use. (blog entry)

class Array
  def mergesort(&cmp)
    if cmp == nil
      cmp = lambda { |a, b| a <=> b }
    end
    if size <= 1
      self.dup
    else
       halves = split.map{ |half|
        half.mergesort(&cmp)
      }
      merge(*halves, &cmp)
    end
  end

 
  protected
  def split
    n = (length / 2).floor - 1
    [self[0..n], self[n+1..-1]]
  end

  def merge(first, second, &predicate)
    result = []
    until first.empty? || second.empty?
     if predicate.call(first.first, second.first) <= 0
        result << first.shift
      else
        result << second.shift
      end 
    end
    result.concat(first).concat(second)
  end
end

Stable Sort

Stable sort method for the Array class. Acts like the original sort method and accepts blocks in the same way. (blog entry)

class Array
  def stable_sort
    n = 0
    c = lambda { |x| n+= 1; [x, n]}
    if block_given?
      sort { |a, b|
        yield(c.call(a), c.call(b))        
      }
    else
      sort_by &c
    end
  end
end

Sorting arrays in Bash


# get a sort command that will sort -print0 output (sort0 below)

#  requires Xcode on Mac OS X
open http://developer.apple.com/technology/Xcode.html

cd ~/Desktop

# Improved GNU sort (from textutils-1.22)
open http://attractivechaos.wordpress.com/2008/08/22/improved-gnu-sort-from-textutils-122/

curl -L -O http://www.freewebs.com/attractivechaos/sort-1.22a.tar.bz2

tar -xjf sort-1.22a.tar.bz2

cd sort-1.22a


# replace
#             int eolchar = '\n';
# with
#             int eolchar = '\0';

cat <<-'EOF' | sed -e 's/^ *//' -e 's/ *$//' | ed -s ~/Desktop/sort-1.22a/sort.c
   H
   /int eolchar = '\\n';/s/\\n/\\0/
   wq
EOF


make


alias sort0=~/Desktop/sort-1.22a/sort


ar1=('g h c' abc def 123)
ar2=('1 2 3' ABC ghc DEF)
ar3=('-x' '! & ?' $'a test\nsentence' $'another test\nsentence\n.' a64bitapp a32bitapp)

printf "%s\n" "${#ar1[@]}" "${#ar2[@]}" "${#ar3[@]}"  

printf "%s\000" "${ar1[@]}" | sort0 | tr '\0' '\n'
printf "%s\000" "${ar1[@]}" | sort0 | while read -d $'\0' item; do echo "index $[i++]:   ${item}"; done

printf "%s\000" "${ar2[@]}" | sort0 | while read -d $'\0' item; do echo "index $[i++]:   ${item}"; done

printf "%s\000" "${ar3[@]}" | sort0 | while read -d $'\0' item; do echo "index $[i++]:   ${item}"; done



# sort & uniq filename suffixes

# encode \n as \777 within the find command, then sort and finally decode \777 as \n again with the tr command
# (also an exercise in single quote usage)

man ruby | less -p 777
find . -type f -name '[^.]*.*' -exec bash -c 'basename=( "${@##*.}" ); printf "%s\n" "${basename[@]//''$'"'\n'"'''/''$'"'\777'"'''}"'  _ '{}' + | \
     sort -u | nl | tr $'\777' '\n'


# same, but using sort0

find . -type f -name '[^.]*.*' -exec bash -c 'printf "%s\000" "${@##*.}"' _ '{}' + | sort0 -u | tr '\0' '\n'

find . -type f -name '[^.]*.*' -exec bash -c 'printf "%s\000" "${@##*.}"' _ '{}' + | \
         sort0 -u | while read -d $'\0' suffix; do echo "$[i++]:   ${suffix}"; done



#----------------------------------------------------------------------------



export PATH="$(/usr/sbin/sysctl -n user.cs_path)"

export IFS=$'\n'
#export IFS=$' \t\n'

ar1=('g h c' abc def 123)
ar2=('1 2 3' ABC ghc DEF)
ar3=('-x' '! & ?' $'a test\nsentence' $'another test\nsentence\n.' a64bitapp a32bitapp)

printf "%s\n" "${#ar1[@]}" "${#ar2[@]}" "${#ar3[@]}"  


# ar3
for ((i=0; i < "${#ar3[@]}"; i++)); do echo "${ar3[$i]}"; done | sort | nl
for ((i=0; i < "${#ar3[@]}"; i++)); do echo ${ar3[$i]}; done | sort | nl
for ((i=0; i < "${#ar3[@]}"; i++)); do echo "${ar3[$i]}" | ruby -0777 -n -e 'p $_.to_s'; done | nl
for ((i=0; i < "${#ar3[@]}"; i++)); do printf -- "${ar3[$i]}\n" | ruby -0777 -n -e 'p $_.to_s'; done | nl


# sort a single array
ar3sorted=( $(for ((i=0; i < "${#ar3[@]}"; i++)); do echo ${ar3[$i]}; done | sort) )
for ((i=0; i < "${#ar3sorted[@]}"; i++)); do echo "${ar3sorted[$i]}" | ruby -0777 -n -e 'p $_.to_s'; done | nl
for ((i=0; i < "${#ar3sorted[@]}"; i++)); do printf "%s\n" "${ar3sorted[$i]}" | ruby -0777 -n -e 'p $_.to_s'; done | nl


# adding \000\n as array item delimiter
printf "%s\000\n" "${ar3[@]}"  | sed -n -e 'l'
printf "%s\000\n" "${ar3[@]}"  | ruby -n -e 'p $_.to_s'
printf "%s\000\n" "${ar3[@]}"  | ruby -0777 -n -e 'p $_.to_s'
printf "%s\000\n" "${ar3[@]}" | sed -e :a -e '$!N; s/\n/NEWLINE/g; ta' | ruby -n -e 'p $_.to_s'
printf "%s\000\n" "${ar3[@]}" | sed -e :a -e '$!N; s/\n/NEWLINE/g; ta' | tr '\000' '\n' | sed -e 's/^NEWLINE//' | ruby -n -e 'p $_.to_s'


ar3sorted=( $(printf "%s\000\n" "${ar3[@]}" | sed -e :a -e '$!N; s/\n/NEWLINE/g; ta' | tr '\000' '\n' | sed -e 's/^NEWLINE//' | sort) )
for ((i=0; i < "${#ar3sorted[@]}"; i++)); do printf -- "${ar3sorted[$i]//NEWLINE/\n}" | ruby -0777 -n -e 'p $_.to_s'; done | nl


# sort multiple arrays; convert embedded newline characters into single spaces
ar4=( $(printf "%s\n\000" "${ar1[@]}" "${ar2[@]}" "${ar3[@]}" | tr '\n' ' ' | tr '\000' '\n' | sort) )

# sort multiple arrays; preserve embedded newline characters as NEWLINE
ar4=( $(printf "%s\000\n" "${ar1[@]}" "${ar2[@]}" "${ar3[@]}" | sed -e :a -e '$!N; s/\n/NEWLINE/g; ta' | tr '\000' '\n' | sed -e 's/^NEWLINE//' | sort) )


printf "%s\n" "${#ar4[@]}"  
printf "%s\n" "${ar4[@]}" | nl  

for ((i=0; i < "${#ar4[@]}"; i++)); do echo ${ar4[$i]//NEWLINE/\\n}; done | nl
for ((i=0; i < "${#ar4[@]}"; i++)); do echo -e ${ar4[$i]//NEWLINE/\\n}; done | nl
for ((i=0; i < "${#ar4[@]}"; i++)); do printf -- ${ar4[$i]//NEWLINE/\\n}"\n"; done | nl
for ((i=0; i < "${#ar4[@]}"; i++)); do printf -- "${ar4[$i]//NEWLINE/\n}\n"; done | nl
for ((i=0; i < "${#ar4[@]}"; i++)); do printf "%s\n" ${ar4[$i]//NEWLINE/\\n}; done | nl
for ((i=0; i < "${#ar4[@]}"; i++)); do printf -- "${ar4[$i]//NEWLINE/\n}\n" | ruby -0777 -n -e 'p $_.to_s'; done | nl
for ((i=0; i < "${#ar4[@]}"; i++)); do printf "%s\n" "${ar4[$i]//NEWLINE/\n}" | ruby -0777 -n -e 'p $_.to_s'; done | nl

sort installed packages by size

// sort installed packages by size

rpm -qa --queryformat="%{size} %{name}-%{version}-%{release}\n" | sort -rn | less

Сортировка массива с городами

// К примеру мне нужен массив с городами(имя, год основания). Отсортировать его(по году основания) и вывести названия городов.
// Чтобы отсортировать массив по населению, надо лишь заменить year на population)

cities = Array.new
cities << { :name => 'SPb',    :year => 1703, :population => 5_000_000 }
cities << { :name => 'Moscow', :year => 1147, :population => 10_000_000_000 }

cities.sort_by { |city| city[:year] }.each do |city|
  puts "#{city[:name]}"
end

Stable sort

c.f. ruby-talk 133930

class Array
  def stable_sort
    n = 0
    sort_by {|x| n+= 1; [x, n]}
  end
end