Recently, I switched from a Powerbook to a Macbook, and to copy my files from one to the other, I used a pen drive. Since my pen drive has a FAT file system, it treats everything as being executable. This, however, is not the case on a UNIX-like file system like OS X. In order to save myself the hassle of manually chmodding thousands of files, I wrote this Ruby script:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#!/usr/bin/env ruby
require 'find'
require 'fileutils'

# Append to/remove from this list as necessary
Plain = ['php', 'txt', 'jpg', 'jpeg', 'gif', 'png', 'html', 'pdf', 'css', 'mp3', 'zip', 'tar.gz', 'tar', 'htm', 'psd', 'ai', 'ptg', 'cgi.pl', 'sphp', 'svn-base', 'default'].collect do |ext|
  ".#{ext}"
end.freeze

# Append to/remove from this list as necessary
Executable = ['pl', 'rb', 'cgi', 'sh'].collect do |ext|
  ".#{ext}"
end.freeze
$num_chmodded = 0

def chmod_and_puts( cmd )
  puts cmd
  system cmd
  $num_chmodded += 1
end

def chmodder( start_dir )
  num_skipped = 0
  num_plain = 0
  num_executable = 0

  Find.find( start_dir ) do |path|
    unless File.symlink?( path )
      if FileTest.file? path
        if is_plain? path
          chmod_and_puts "chmod 644 \"#{path}\""
          num_plain += 1
        elsif is_executable? path
          chmod_and_puts "chmod 755 \"#{path}\""
          num_executable += 1
        else
          num_skipped += 1
        end
      elsif File.directory? path
        chmod_and_puts "chmod 755 \"#{path}\""
        num_executable += 1
      else
        num_skipped += 1
      end
    else
      num_skipped += 1
    end
  end

  puts "----------------------------------------------"
  puts "Chmodded #{$num_chmodded} total:"
  puts "\tExecutable: #{num_executable}"
  puts "\tPlain: #{num_plain}"
  puts "Skipped #{num_skipped} files/directories/symlinks"
end

def get_extension( path )
  File.extname( path ).downcase
end

def is_executable?( path )
  extension = get_extension( path )

  if Executable.include? extension
    true
  else
    false
  end
end

def is_plain?( path )
  extension = get_extension( path )

  if Plain.include? extension
    true
  else
    false
  end
end

chmodder( '.' )

This goes through all the files and directories within the directory from which you run the script and chmods non-executable files to 644 (read+write on User, read on Group and Other) and executable files to 755 (read+write+execute on User, read+execute on Group and Other). If you’re unfamiliar with the chmod command, you might want to read my beginning Linux guide.