File Coverage

blib/lib/String/ShellQuote.pm
Criterion Covered Total %
statement 55 55 100.0
branch 19 20 95.0
condition 6 9 66.6
subroutine 7 7 100.0
pod 3 4 75.0
total 90 95 94.7


line stmt bran cond sub pod time code
1             # $Id: ShellQuote.pm,v 1.11 2010-06-11 20:08:57 roderick Exp $
2             #
3             # Copyright (c) 1997 Roderick Schertler. All rights reserved. This
4             # program is free software; you can redistribute it and/or modify it
5             # under the same terms as Perl itself.
6              
7             =head1 NAME
8              
9             String::ShellQuote - quote strings for passing through the shell
10              
11             =head1 SYNOPSIS
12              
13             $string = shell_quote @list;
14             $string = shell_quote_best_effort @list;
15             $string = shell_comment_quote $string;
16              
17             =head1 DESCRIPTION
18              
19             This module contains some functions which are useful for quoting strings
20             which are going to pass through the shell or a shell-like object.
21              
22             =over
23              
24             =cut
25              
26             package String::ShellQuote;
27              
28 5     5   586 use strict;
  5         9  
  5         157  
29 5     5   24 use vars qw($VERSION @ISA @EXPORT);
  5         6  
  5         4027  
30              
31             require Exporter;
32              
33             $VERSION = '1.04';
34             @ISA = qw(Exporter);
35             @EXPORT = qw(shell_quote shell_quote_best_effort shell_comment_quote);
36              
37             sub croak {
38 2     2 0 15 require Carp;
39 2         359 goto &Carp::croak;
40             }
41              
42             sub _shell_quote_backend {
43 27     27   45 my @in = @_;
44 27         37 my @err = ();
45              
46 27         28 if (0) {
47             require RS::Handy;
48             print RS::Handy::data_dump(\@in);
49             }
50              
51 27 100       65 return \@err, '' unless @in;
52              
53 25         36 my $ret = '';
54 25         24 my $saw_non_equal = 0;
55 25         39 foreach (@in) {
56 35 100 100     148 if (!defined $_ or $_ eq '') {
57 5         7 $_ = "''";
58 5         8 next;
59             }
60              
61 30 100       72 if (s/\x00//g) {
62 2         4 push @err, "No way to quote string containing null (\\000) bytes";
63             }
64              
65 30         35 my $escape = 0;
66              
67             # = needs quoting when it's the first element (or part of a
68             # series of such elements), as in command position it's a
69             # program-local environment setting
70              
71 30 100       57 if (/=/) {
72 3 50       8 if (!$saw_non_equal) {
73 3         4 $escape = 1;
74             }
75             }
76             else {
77 27         32 $saw_non_equal = 1;
78             }
79              
80 30 100       133 if (m|[^\w!%+,\-./:=@^]|) {
81 15         17 $escape = 1;
82             }
83              
84 30 100 33     132 if ($escape
      66        
85             || (!$saw_non_equal && /=/)) {
86              
87             # ' -> '\''
88 18         36 s/'/'\\''/g;
89              
90             # make multiple ' in a row look simpler
91             # '\'''\'''\'' -> '"'''"'
92 18         28 s|((?:'\\''){2,})|q{'"} . (q{'} x (length($1) / 4)) . q{"'}|ge;
  1         10  
93              
94 18         29 $_ = "'$_'";
95 18         26 s/^''//;
96 18         29 s/''$//;
97             }
98             }
99             continue {
100 35         95 $ret .= "$_ ";
101             }
102              
103 25         35 chop $ret;
104 25         75 return \@err, $ret;
105             }
106              
107             =item B [I]...
108              
109             B quotes strings so they can be passed through the shell.
110             Each I is quoted so that the shell will pass it along as a
111             single argument and without further interpretation. If no Is
112             are given an empty string is returned.
113              
114             If any I can't be safely quoted B will B.
115              
116             =cut
117              
118             sub shell_quote {
119 22     22 1 430 my ($rerr, $s) = _shell_quote_backend @_;
120              
121 22 100       64 if (@$rerr) {
122 1         1 my %seen;
123 1         11 @$rerr = grep { !$seen{$_}++ } @$rerr;
  1         6  
124 1         3 my $s = join '', map { "shell_quote(): $_\n" } @$rerr;
  1         6  
125 1         2 chomp $s;
126 1         5 croak $s;
127             }
128 21         114 return $s;
129             }
130              
131             =item B [I]...
132              
133             This is like B, excpet if the string can't be safely quoted
134             it does the best it can and returns the result, instead of dying.
135              
136             =cut
137              
138             sub shell_quote_best_effort {
139 5     5 1 121 my ($rerr, $s) = _shell_quote_backend @_;
140              
141 5         15 return $s;
142             }
143              
144             =item B [I]
145              
146             B quotes the I so that it can safely be
147             included in a shell-style comment (the current algorithm is that a sharp
148             character is placed after any newlines in the string).
149              
150             This routine might be changed to accept multiple I arguments
151             in the future. I haven't done this yet because I'm not sure if the
152             Is should be joined with blanks ($") or nothing ($,). Cast
153             your vote today! Be sure to justify your answer.
154              
155             =cut
156              
157             sub shell_comment_quote {
158 5 100   5 1 131 return '' unless @_;
159 4 100       9 unless (@_ == 1) {
160 1         5 croak "Too many arguments to shell_comment_quote "
161             . "(got " . @_ . " expected 1)";
162             }
163 3         6 local $_ = shift;
164 3         8 s/\n/\n#/g;
165 3         29 return $_;
166             }
167              
168             1;
169              
170             __END__