Seasons.NET

ちょっとした技術ブログです

サーバーの設定をバックアップするスクリプト

Linux等のサーバー設定ファイルだけ抜き出したい時に、
Findで探せばいいんだけど、ルートに対して行うことは、負荷が高くなる上に
使い勝手がよくない。

ということで以下のような感じで使えるスクリプトを書いてみました。
保存する時は、backupfilesで保存してもらえればOKです。

7 backupfiles -o /home/seasons -i /etc/ -v -m "\.conf|\.sh|\.rb|\/\.[A-Za-z]+$"

以下スクリプト本体。

  1 #!/usr/bin/ruby -Ku
  2 require 'find'
  3 require 'pathname'
  4 require 'fileutils'
  5 require 'optparse'
  6 require 'pp'
  7 
  8 $KCODE = "u"
  9 
 10 # =========================================================================
 11 # Extension Pathname util
 12 class String
 13 
 14   # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
 15   # to_path method
 16   #
 17   # exp)
 18   # path = '/usr/local/test.txt'
 19   # path = path.to_path
 20   #
 21   # p path.to_s  #=> '/usr/local/test.txt'
 22   # p path.file? #=> true
 23   #
 24   def to_path
 25 
 26     Pathname.new( self )
 27 
 28   end
 29 
 30 end
 31 
 32 # =========================================================================
 33 # Extension Pathname tools
 34 class Pathname
 35 
 36   # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
 37   # Show Path -> As String
 38   #
 39   def name
 40 
 41     self.to_s
 42 
 43   end
 44 
 45   # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
 46   # Join Path + FilePath
 47   # 
 48   # args)
 49   # file ... filepath
 50   #
 51   # exp)
 52   #
 53   # path = '/usr/local/devel'
 54   # path = path.to_path!
 55   # path.joinpath( './test.txt' ).name #=> /usr/local/devel/test.txt
 56   #
 57   def joinpath( file )
 58 
 59     filepath = file.to_path
 60     return nil unless filepath.exist?
 61     newpath = (self + filepath).cleanpath
 62 
 63   end
 64 
 65 end
 66 
 67 # =========================================================================
 68 # Find Extension
 69 class FindPowerToys
 70 
 71   # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
 72   # initialize
 73   #
 74   # args)
 75   # searchpath ... searchpath
 76   #
 77   def initialize( searchpath )
 78 
 79     @searchpath = searchpath.to_path
 80     @filelist = []
 81     raise ArgumentError , "### searchpath is not found!! => #{searchpath}" unless @searchpath.exist?
 82     Find.find( @searchpath.name ){ |fname| @filelist << fname }
 83     @filelist = @filelist.select{ |item| @searchpath.joinpath( item ) if @searchpath.joinpath( item ) }
 84     @filelist.map!{ |item| @searchpath.joinpath( item ).name }
 85 
 86   end
 87 
 88 
 89   # -----------------------------------------------------------------
 90   # Entry file items(iterator)
 91   #
 92   # exp)
 93   # fp = FindPowerToys.new('/')
 94   # fp.files do |fname|
 95   #  p fname #=> Show Root=/ FileEntries
 96   # end
 97   #
 98   def files
 99 
100     @filelist.each do |item|
101       yield item
102     end
103 
104   end
105 
106 end
107 
108 # ==========================================================================
109 # File Copy Extension
110 #
111 # args)
112 # dstpath ... destination file path
113 # srcpath ... source file path
114 # verbose ... verbose show output
115 #
116 # exp)
117 # FileCopyUtils.copyr( '/home/seasons/' , '/usr/local/hoge.txt' )
118 #
119 # /usr/local/hoge.txt -> /home/seasons/usr/local/hoge.txt
120 #
121 class FileCopyUtils
122 
123   def FileCopyUtils.copyr( dstpath , srcpath , verbose=false )
124 
125     # Check valid path
126     srcpath = srcpath.to_path
127     return unless srcpath.file?
128 
129     dstpath = dstpath.to_path
130     raise ArgumentError , "### Filepath is not found!! => #{srcpath}" unless srcpath.exist?
131     raise ArgumentError , "### Filepath is not found!! => #{dstpath}" unless dstpath.exist?
132 
133     # Create Recursive Directory
134     dstpath += '.' + srcpath.name
135     dstpath = dstpath.cleanpath
136     dir = File.dirname( dstpath.name )
137     FileUtils.mkdir_p( dir ) unless FileTest.exist? dir
138 
139     # Copy Files
140     FileUtils.cp( srcpath.name , dstpath.name )
141     print "#{srcpath.name} -> #{dstpath.name}\n" if verbose
142 
143   end
144 
145 end
146 
147 # ==========================================================================
148 # Main
149 # ==========================================================================
150 def main
151 
152   #=> Parser
153   outputPath = nil
154   inputPath  = nil
155   patternMatch  = nil
156   verbose    = false
157   parser        = OptionParser.new
158   parser.banner = "\nUsage: #{$0} -o OUTPUTPATH -i INPUTPATH -m MATCHPATTERN\n[mailto]: keisuke@hata.biz"
159   parser.on( '-o' , '--output=OUTPUTPATH' ){ |output| outputPath = output }
160   parser.on( '-i' , '--input=INPUTPATH'   ){ |input|  inputPath  = input  }
161   parser.on( '-m' , '--match=MATCHPATTERN'){ |pattern|  patternMatch  = pattern }
162   parser.on( '-v' ){ |verboseflg| verbose = verboseflg  }
163 
164   def parser.error(msg = nil)
165     $stderr.puts msg if msg
166     $stderr.puts help()
167     exit 1
168   end
169   begin
170     parser.parse!
171   rescue OptionParser::ParseError => err
172     parser.error err.message
173   end
174   parser.error '### no output path'      unless outputPath
175   parser.error '### output is not path' unless outputPath.to_path.directory?
176   parser.error '### no intput path'      unless inputPath
177   parser.error '### intput is not path' unless inputPath.to_path.directory?
178   parser.error '### ARGV is Empty'     unless ARGV.empty?
179 
180   #=> FileBackup
181   match = nil
182   match = Regexp.new(/#{patternMatch}/)
183   fp = FindPowerToys.new( inputPath )
184   fp.files do |fname|
185     if !match or (match and fname =~ match)
186       FileCopyUtils.copyr( outputPath , fname , verbose )
187     end
188   end
189 end
190 
191 main() if __FILE__ == $0