# shellwords.rb: Manipulates strings a la UNIX Bourne shell
# 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).
# - Akinori MUSHA <knu@iDaemons.org>
# - Akinori MUSHA <knu@iDaemons.org> (current maintainer)
# Splits a string into an array of tokens in the same way the UNIX
# 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"]
line = String.new(line) rescue
raise(ArgumentError, "Argument must be a string")
if line.sub!(/\A"(([^"\\]|\\.)*)"/, '') then
snippet = $1.gsub(/\\(.)/, '\1')
raise ArgumentError, "Unmatched double quote: #{line}"
elsif line.sub!(/\A'([^']*)'/, '') then
raise ArgumentError, "Unmatched single quote: #{line}"
elsif line.sub!(/\A\\(.)?/, '') then
elsif line.sub!(/\A([^\s\\'"]+)/, '') then
alias shellwords shellsplit
module_function :shellsplit, :shellwords
# Escapes a string so that it can be safely used in a Bourne shell
# 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|
# An empty argument will be skipped, so return empty quotes.
return "''" if str.empty?
# 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.
module_function :shellescape
# 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|
array.map { |arg| shellescape(arg) }.join(' ')
module_function :shelljoin
# str.shellsplit => array
# Splits +str+ into an array of tokens in the same way the UNIX
# Bourne shell does. See +Shellwords::shellsplit+ for details.
# str.shellescape => string
# Escapes +str+ so that it can be safely used in a Bourne shell
# command line. See +Shellwords::shellescape+ for details.
# array.shelljoin => string
# Builds a command line string from an argument list +array+ joining
# all elements escaped for Bourne shell and separated by a space.
# See +Shellwords::shelljoin+ for details.