summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog6
-rw-r--r--lib/shellwords.rb14
-rw-r--r--test/test_shellwords.rb22
3 files changed, 34 insertions, 8 deletions
diff --git a/ChangeLog b/ChangeLog
index e179050d11..2091ce07b5 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+Sat Nov 5 13:52:52 2016 Akinori MUSHA <knu@iDaemons.org>
+
+ * lib/shellwords.rb (Shellwords#shellsplit): Fix the handling of
+ the backslash in double quotes to conform to the standard.
+ [ruby-core:63807] [Bug #10055]
+
Sat Nov 5 12:14:31 2016 Tanaka Akira <akr@fsij.org>
* ext/pathname/pathname.c (Pathname#empty?): New method.
diff --git a/lib/shellwords.rb b/lib/shellwords.rb
index 0030f0784f..eb5fa2d226 100644
--- a/lib/shellwords.rb
+++ b/lib/shellwords.rb
@@ -6,7 +6,8 @@
# 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 [1]).
+# but modified to conform to the Shell & Utilities volume of the IEEE
+# Std 1003.1-2008, 2016 Edition [1].
#
# === Usage
#
@@ -55,7 +56,7 @@
#
# === Resources
#
-# 1: {IEEE Std 1003.1-2004}[http://pubs.opengroup.org/onlinepubs/009695399/toc.htm]
+# 1: {IEEE Std 1003.1-2008, 2016 Edition, the Shell & Utilities volume}[http://pubs.opengroup.org/onlinepubs/9699919799/utilities/contents.html]
module Shellwords
# Splits a string into an array of tokens in the same way the UNIX
@@ -81,7 +82,14 @@ module Shellwords
line.scan(/\G\s*(?>([^\s\\\'\"]+)|'([^\']*)'|"((?:[^\"\\]|\\.)*)"|(\\.?)|(\S))(\s|\z)?/m) do
|word, sq, dq, esc, garbage, sep|
raise ArgumentError, "Unmatched double quote: #{line.inspect}" if garbage
- field << (word || sq || (dq || esc).gsub(/\\(.)/, '\\1'))
+ # 2.2.3 Double-Quotes:
+ #
+ # The <backslash> shall retain its special meaning as an
+ # escape character only when followed by one of the following
+ # characters when considered special:
+ #
+ # $ ` " \ <newline>
+ field << (word || sq || (dq && dq.gsub(/\\([$`"\\\n])/, '\\1')) || esc.gsub(/\\(.)/, '\\1'))
if sep
words << field
field = String.new
diff --git a/test/test_shellwords.rb b/test/test_shellwords.rb
index 2916d5dda6..16949c02d3 100644
--- a/test/test_shellwords.rb
+++ b/test/test_shellwords.rb
@@ -40,12 +40,24 @@ class TestShellwords < Test::Unit::TestCase
end
def test_backslashes
- cmdline, expected = [
- %q{/a//b///c////d/////e/ "/a//b///c////d/////e/ "'/a//b///c////d/////e/ '/a//b///c////d/////e/ },
- %q{a/b/c//d//e a/b/c//d//e /a//b///c////d/////e/ a/b/c//d//e }
- ].map { |str| str.tr("/", "\\\\") }
- assert_equal [expected], shellwords(cmdline)
+ [
+ [
+ %q{/a//b///c////d/////e/ "/a//b///c////d/////e/ "'/a//b///c////d/////e/ '/a//b///c////d/////e/ },
+ 'a/b/c//d//e /a/b//c//d///e/ /a//b///c////d/////e/ a/b/c//d//e '
+ ],
+ [
+ %q{printf %s /"/$/`///"/r/n},
+ 'printf', '%s', '"$`/"rn'
+ ],
+ [
+ %q{printf %s "/"/$/`///"/r/n"},
+ 'printf', '%s', '"$`/"/r/n'
+ ]
+ ].map { |strs|
+ cmdline, *expected = strs.map { |str| str.tr("/", "\\\\") }
+ assert_equal expected, shellwords(cmdline)
+ }
end
def test_stringification