* io.c (rb_open_file): encoding in mode string was ignored if perm is
[ruby-svn.git] / lib / shellwords.rb
blobf1300612bb69a845d573a15e77a37f0070d5310f
2 # shellwords.rb: Manipulates strings a la UNIX Bourne shell
6 # This module manipulates strings according to the word parsing rules
7 # of the UNIX Bourne shell.
9 # The shellwords() function was originally a port of shellwords.pl,
10 # but modified to conform to POSIX / SUSv3 (IEEE Std 1003.1-2001).
12 # Authors:
13 #   - Wakou Aoyama
14 #   - Akinori MUSHA <knu@iDaemons.org>
16 # Contact:
17 #   - Akinori MUSHA <knu@iDaemons.org> (current maintainer)
19 module Shellwords
20   #
21   # Splits a string into an array of tokens in the same way the UNIX
22   # Bourne shell does.
23   #
24   #   argv = Shellwords.split('here are "two words"')
25   #   argv #=> ["here", "are", "two words"]
26   #
27   # +String#shellsplit+ is a shorthand for this function.
28   #
29   #   argv = 'here are "two words"'.shellsplit
30   #   argv #=> ["here", "are", "two words"]
31   #
32   def shellsplit(line)
33     words = []
34     field = ''
35     line.scan(/\G\s*(?>([^\s\\\'\"]+)|'([^\']*)'|"((?:[^\"\\]|\\.)*)"|(\\.?)|(\S))(\s|\z)?/m) do
36       |word, sq, dq, esc, garbage, sep|
37       raise ArgumentError, "Unmatched double quote: #{line.inspect}" if garbage
38       field << (word || sq || (dq || esc).gsub(/\\(?=.)/, ''))
39       if sep
40         words << field
41         field = ''
42       end
43     end
44     words
45   end
47   alias shellwords shellsplit
49   module_function :shellsplit, :shellwords
51   class << self
52     alias split shellsplit
53   end
55   #
56   # Escapes a string so that it can be safely used in a Bourne shell
57   # command line.
58   #
59   # Note that a resulted string should be used unquoted and is not
60   # intended for use in double quotes nor in single quotes.
61   #
62   #   open("| grep #{Shellwords.escape(pattern)} file") { |pipe|
63   #     # ...
64   #   }
65   #
66   # +String#shellescape+ is a shorthand for this function.
67   #
68   #   open("| grep #{pattern.shellescape} file") { |pipe|
69   #     # ...
70   #   }
71   #
72   def shellescape(str)
73     # An empty argument will be skipped, so return empty quotes.
74     return "''" if str.empty?
76     str = str.dup
78     # Process as a single byte sequence because not all shell
79     # implementations are multibyte aware.
80     str.gsub!(/([^A-Za-z0-9_\-.,:\/@\n])/n, "\\\\\\1")
82     # A LF cannot be escaped with a backslash because a backslash + LF
83     # combo is regarded as line continuation and simply ignored.
84     str.gsub!(/\n/, "'\n'")
86     return str
87   end
89   module_function :shellescape
91   class << self
92     alias escape shellescape
93   end
95   #
96   # Builds a command line string from an argument list +array+ joining
97   # all elements escaped for Bourne shell and separated by a space.
98   #
99   #   open('|' + Shellwords.join(['grep', pattern, *files])) { |pipe|
100   #     # ...
101   #   }
102   #
103   # +Array#shelljoin+ is a shorthand for this function.
104   #
105   #   open('|' + ['grep', pattern, *files].shelljoin) { |pipe|
106   #     # ...
107   #   }
108   #
109   def shelljoin(array)
110     array.map { |arg| shellescape(arg) }.join(' ')
111   end
113   module_function :shelljoin
115   class << self
116     alias join shelljoin
117   end
120 class String
121   #
122   # call-seq:
123   #   str.shellsplit => array
124   #
125   # Splits +str+ into an array of tokens in the same way the UNIX
126   # Bourne shell does.  See +Shellwords::shellsplit+ for details.
127   #
128   def shellsplit
129     Shellwords.split(self)
130   end
132   #
133   # call-seq:
134   #   str.shellescape => string
135   #
136   # Escapes +str+ so that it can be safely used in a Bourne shell
137   # command line.  See +Shellwords::shellescape+ for details.
138   #
139   def shellescape
140     Shellwords.escape(self)
141   end
144 class Array
145   #
146   # call-seq:
147   #   array.shelljoin => string
148   #
149   # Builds a command line string from an argument list +array+ joining
150   # all elements escaped for Bourne shell and separated by a space.
151   # See +Shellwords::shelljoin+ for details.
152   #
153   def shelljoin
154     Shellwords.join(self)
155   end