Module: Shellwords

Defined in:
lib/ext/shellwords.rb

Overview

This module manipulates strings according to the word parsing rules of the UNIX Bourne shell.

The shellwords() function was originally a port of shellwords.pl, but modified to conform to POSIX / SUSv3 (IEEE Std 1003.1-2001).

Authors:

- Wakou Aoyama
- Akinori MUSHA <[email protected]>

Contact:

- Akinori MUSHA <[email protected]> (current maintainer)

Class Method Summary collapse

Class Method Details

.shellescape(str) ⇒ Object Also known as: escape

Escapes a string so that it can be safely used in a Bourne shell command line.

Note that a resulted string should be used unquoted and is not intended for use in double quotes nor in single quotes.

open("| grep #{Shellwords.escape(pattern)} file") { |pipe|
  # ...
}

String#shellescape is a shorthand for this function.

open("| grep #{pattern.shellescape} file") { |pipe|
  # ...
}


88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/ext/shellwords.rb', line 88

def shellescape(str)
  # An empty argument will be skipped, so return empty quotes.
  return "''" if str.empty?

  str = str.dup

  # Process as a single byte sequence because not all shell
  # implementations are multibyte aware.
  str.gsub!(/([^A-Za-z0-9_\-.,:\/@\n])/n, "\\\\\\1")

  # A LF cannot be escaped with a backslash because a backslash + LF
  # combo is regarded as line continuation and simply ignored.
  str.gsub!(/\n/, "'\n'")

  return str
end

.shelljoin(array) ⇒ Object Also known as: join

Builds a command line string from an argument list array joining all elements escaped for Bourne shell and separated by a space.

open('|' + Shellwords.join(['grep', pattern, *files])) { |pipe|
  # ...
}

Array#shelljoin is a shorthand for this function.

open('|' + ['grep', pattern, *files].shelljoin) { |pipe|
  # ...
}


125
126
127
# File 'lib/ext/shellwords.rb', line 125

def shelljoin(array)
  array.map { |arg| shellescape(arg) }.join(' ')
end

.shellsplit(line) ⇒ Object Also known as: split

Splits a string into an array of tokens in the same way the UNIX Bourne shell does.

argv = Shellwords.split('here are "two words"')
argv #=> ["here", "are", "two words"]

String#shellsplit is a shorthand for this function.

argv = 'here are "two words"'.shellsplit
argv #=> ["here", "are", "two words"]


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
# File 'lib/ext/shellwords.rb', line 32

def shellsplit(line)
  line = String.new(line) rescue
    raise(ArgumentError, "Argument must be a string")
  line.lstrip!
  words = []
  until line.empty?
    field = ''
    loop do
	if line.sub!(/\A"(([^"\\]|\\.)*)"/, '') then
 snippet = $1.gsub(/\\(.)/, '\1')
	elsif line =~ /\A"/ then
 raise ArgumentError, "Unmatched double quote: #{line}"
	elsif line.sub!(/\A'([^']*)'/, '') then
 snippet = $1
	elsif line =~ /\A'/ then
 raise ArgumentError, "Unmatched single quote: #{line}"
	elsif line.sub!(/\A\\(.)?/, '') then
 snippet = $1 || '\\'
	elsif line.sub!(/\A([^\s\\'"]+)/, '') then
 snippet = $1
	else
 line.lstrip!
 break
	end
	field.concat(snippet)
    end
    words.push(field)
  end
  words
end

.shellwordsObject

Splits a string into an array of tokens in the same way the UNIX Bourne shell does.

argv = Shellwords.split('here are "two words"')
argv #=> ["here", "are", "two words"]

String#shellsplit is a shorthand for this function.

argv = 'here are "two words"'.shellsplit
argv #=> ["here", "are", "two words"]


63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/ext/shellwords.rb', line 63

def shellsplit(line)
  line = String.new(line) rescue
    raise(ArgumentError, "Argument must be a string")
  line.lstrip!
  words = []
  until line.empty?
    field = ''
    loop do
	if line.sub!(/\A"(([^"\\]|\\.)*)"/, '') then
 snippet = $1.gsub(/\\(.)/, '\1')
	elsif line =~ /\A"/ then
 raise ArgumentError, "Unmatched double quote: #{line}"
	elsif line.sub!(/\A'([^']*)'/, '') then
 snippet = $1
	elsif line =~ /\A'/ then
 raise ArgumentError, "Unmatched single quote: #{line}"
	elsif line.sub!(/\A\\(.)?/, '') then
 snippet = $1 || '\\'
	elsif line.sub!(/\A([^\s\\'"]+)/, '') then
 snippet = $1
	else
 line.lstrip!
 break
	end
	field.concat(snippet)
    end
    words.push(field)
  end
  words
end