String-ShellQuote-1.04/0000755000175000017500000000000011404514012015145 5ustar roderickroderickString-ShellQuote-1.04/shell-quote0000755000175000017500000001253011404512730017343 0ustar roderickroderick#!perl -w use strict; # $Id: shell-quote,v 1.3 2010-06-11 20:00:24 roderick Exp $ # # Roderick Schertler # Copyright (C) 1999 Roderick Schertler # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or (at # your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # For a copy of the GNU General Public License write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA use String::ShellQuote qw(shell_quote); (my $Me = $0 ne '-e' ? $0 : $^X) =~ s-.*/--; my $Debug = 0; my $Exit = 0; my $Version = q$Revision: 1.3 $ =~ /(\d\S+)/ ? $1 : '?'; my @Option_spec = ( 'debug!' => \$Debug, 'help!' => sub { usage() }, 'version' => sub { print "$Me version $Version\n"; exit }, ); my $Usage = <VERSION(2.19); Getopt::Long::Configure( 'no_auto_abbrev', 'no_getopt_compat', 'require_order', $bundling ? 'bundling' : (), 'no_ignore_case', 'prefix_pattern=(--|-)', ) if 1; # The getopt function puts the vars into its caller's package so # it's necessary to jump to it so that its caller is my caller. #goto &Getopt::Long::GetOptions; Getopt::Long::GetOptions(@_); } sub init { getopt -bundle, @Option_spec or usage if @ARGV; } sub main { init; print shell_quote(@ARGV), "\n" if @ARGV; return 0; } $Exit = main || $Exit; $Exit = 1 if $Exit && !($Exit % 256); exit $Exit; __END__ =head1 NAME shell-quote - quote arguments for safe use, unmodified in a shell command =head1 SYNOPSIS B [I]... I... =head1 DESCRIPTION B lets you pass arbitrary strings through the shell so that they won't be changed by the shell. This lets you process commands or files with embedded white space or shell globbing characters safely. Here are a few examples. =head1 EXAMPLES =over =item B When running a remote command with ssh, ssh doesn't preserve the separate arguments it receives. It just joins them with spaces and passes them to C<$SHELL -c>. This doesn't work as intended: ssh host touch 'hi there' # fails It creates 2 files, F and F. Instead, do this: cmd=`shell-quote touch 'hi there'` ssh host "$cmd" This gives you just 1 file, F. =item B It's not ordinarily possible to process an arbitrary list of files output by B with a shell script. Anything you put in $IFS to split up the output could legitimately be in a file's name. Here's how you can do it using B: eval set -- `find -type f -print0 | xargs -0 shell-quote --` =item B B is better than B for debugging shell scripts. debug() { [ -z "$debug" ] || shell-quote "debug:" "$@" } With B you can't tell the difference between C and C, but with B you can. =item B B can be used to build up a shell command to run later. Say you want the user to be able to give you switches for a command you're going to run. If you don't want the switches to be re-evaluated by the shell (which is usually a good idea, else there are things the user can't pass through), you can do something like this: user_switches= while [ $# != 0 ] do case x$1 in x--pass-through) [ $# -gt 1 ] || die "need an argument for $1" user_switches="$user_switches "`shell-quote -- "$2"` shift;; # process other switches esac shift done # later eval "shell-quote some-command $user_switches my args" =back =head1 OPTIONS =over 4 =item B<--debug> Turn debugging on. =item B<--help> Show the usage message and die. =item B<--version> Show the version number and exit. =back =head1 AVAILABILITY The code is licensed under the GNU GPL. Check http://www.argon.org/~roderick/ or CPAN for updated versions. =head1 AUTHOR Roderick Schertler =cut String-ShellQuote-1.04/META.yml0000664000175000017500000000073611404514012016426 0ustar roderickroderick--- #YAML:1.0 name: String-ShellQuote version: 1.04 abstract: ~ author: [] license: unknown distribution_type: module configure_requires: ExtUtils::MakeMaker: 0 build_requires: ExtUtils::MakeMaker: 0 requires: {} no_index: directory: - t - inc generated_by: ExtUtils::MakeMaker version 6.55_02 meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: 1.4 String-ShellQuote-1.04/Changes0000644000175000017500000000171611404512730016452 0ustar roderickroderickRevision history for Perl extension String::ShellQuote. 1.04 Mon Jun 7 09:09:36 EDT 2010 - Don't escape "=" unless it's in command position. Thanks to Chip for the inspiration. - Use "#!perl" in test.t (closes #38072). - Don't try to test or install the shell-quote script on Windows (closes #46445). 1.03 Tue May 3 06:47:39 EDT 2005 - Add shell-quote script. 1.02 Thu Feb 10 22:08:27 EST 2005 - Allow qw(! % + , : @ ^) to appear without being quoted. (This was in 1.01, but I forgot to mention it.) 1.01 Wed Feb 9 20:43:46 EST 2005 - Have shell_quote() croak if the string can't be encoded (currently, if it contains NULs). - Add shell_quote_best_effort() which will return what it can instead. 1.00 Sun Dec 07 12:03:36 EST 1997 - In shell_quote, drop leading and trailing ''. 0.01 Tue May 13 22:29:27 EDT 1997 - Initial version. $Id: Changes,v 1.6 2010-06-11 20:00:24 roderick Exp $ String-ShellQuote-1.04/MANIFEST0000644000175000017500000000022510235654055016312 0ustar roderickroderick $Id: MANIFEST,v 1.4 2005/05/03 10:53:33 roderick Exp $ Changes MANIFEST MANIFEST.SKIP META.yml Makefile.PL README ShellQuote.pm shell-quote test.t String-ShellQuote-1.04/test.t0000644000175000017500000000516511404513731016327 0ustar roderickroderick#!perl -w use strict; # $Id: test.t,v 1.6 2010-06-11 20:08:57 roderick Exp $ # # Copyright (c) 1997 Roderick Schertler. All rights reserved. This # program is free software; you can redistribute it and/or modify it # under the same terms as Perl itself. BEGIN { $| = 1; print "1..33\n"; } use String::ShellQuote; my $test_num = 0; sub ok { my ($result, @info) = @_; $test_num++; if ($result) { print "ok $test_num\n"; } else { print "not ok $test_num\n"; print "# ", @info, "\n" if @info; } } my $testsub; sub test { my ($want, @args) = @_; my $pid = $$; my $got = eval { &$testsub(@args) }; exit if $$ != $pid; if ($@) { chomp $@; $@ =~ s/ at \S+ line \d+\.?\z//; $got = "die: $@"; } my $from_line = (caller)[2]; ok $got eq $want, qq{line $from_line\n# wanted [$want]\n# got [$got]}; } $testsub = \&shell_quote; test ''; test q{''}, ''; test q{''}, undef; test q{foo}, qw(foo); test q{foo bar}, qw(foo bar); test q{'foo*'}, qw(foo*); test q{'foo bar'}, q{foo bar}; test q{'foo'\''bar'}, qw(foo'bar); test q{\''foo'}, qw('foo); test q{foo 'bar*'}, qw(foo bar*); test q{'foo'\''foo' bar 'baz'\'}, qw(foo'foo bar baz'); test q{'\'}, qw(\\); test q{\'}, qw('); test q{'\'\'}, qw(\'); test q{'a'"''"'b'}, qw(a''b); test q{azAZ09_!%+,-./:@^}, q{azAZ09_!%+,-./:@^}; test q{'foo=bar' command}, qw(foo=bar command); test q{'foo=bar' 'baz=quux' command}, qw(foo=bar baz=quux command); test "die: shell_quote(): No way to quote string containing null (\\000) bytes", "t\x00"; $testsub = \&shell_quote_best_effort; test ''; test q{''}, ''; test q{''}, undef; test q{'foo*'}, 'foo*'; test q{'foo*' asdf}, 'foo*', "as\x00df"; $testsub = \&shell_comment_quote; test ''; test qq{foo}, qq{foo}; test qq{foo\n#bar}, qq{foo\nbar}; test qq{foo\n#bar\n#baz}, qq{foo\nbar\nbaz}; test "die: Too many arguments to shell_comment_quote (got 2 expected 1)", 'foo', 'bar'; sub via_shell { my @args = @_; my $cmd = 'blib/script/shell-quote'; my $pid = open PIPE, '-|'; defined $pid or return "can't fork: $!\n"; if (!$pid) { if (!open STDERR, '>&STDOUT') { print "$0: can't dup stdout: $!\n"; exit 1; } exec $cmd, @args or die "$0: can't run $cmd: $!\n"; } my $r = join '', ; if (!close PIPE) { $r .= "$cmd failed: " . ($! ? $! : "non-zero exit $?") . "\n"; } return $r; } if ($^O eq 'MSWin32') { print "ok # skip not working on MSWin32\n" x 4; } else { $testsub = \&via_shell; test ''; test qq{a\n}, 'a'; test qq{''\n}, ''; test qq{foo 'bar baz' '*'\n}, 'foo', 'bar baz', '*'; } String-ShellQuote-1.04/MANIFEST.SKIP0000644000175000017500000000012106312303400017034 0ustar roderickroderick# $Id: MANIFEST.SKIP,v 1.2 1997/03/14 17:12:32 roderick Exp $ ,v$ ~$ ^Makefile$ String-ShellQuote-1.04/ShellQuote.pm0000644000175000017500000001003511404513731017576 0ustar roderickroderick# $Id: ShellQuote.pm,v 1.11 2010-06-11 20:08:57 roderick Exp $ # # Copyright (c) 1997 Roderick Schertler. All rights reserved. This # program is free software; you can redistribute it and/or modify it # under the same terms as Perl itself. =head1 NAME String::ShellQuote - quote strings for passing through the shell =head1 SYNOPSIS $string = shell_quote @list; $string = shell_quote_best_effort @list; $string = shell_comment_quote $string; =head1 DESCRIPTION This module contains some functions which are useful for quoting strings which are going to pass through the shell or a shell-like object. =over =cut package String::ShellQuote; use strict; use vars qw($VERSION @ISA @EXPORT); require Exporter; $VERSION = '1.04'; @ISA = qw(Exporter); @EXPORT = qw(shell_quote shell_quote_best_effort shell_comment_quote); sub croak { require Carp; goto &Carp::croak; } sub _shell_quote_backend { my @in = @_; my @err = (); if (0) { require RS::Handy; print RS::Handy::data_dump(\@in); } return \@err, '' unless @in; my $ret = ''; my $saw_non_equal = 0; foreach (@in) { if (!defined $_ or $_ eq '') { $_ = "''"; next; } if (s/\x00//g) { push @err, "No way to quote string containing null (\\000) bytes"; } my $escape = 0; # = needs quoting when it's the first element (or part of a # series of such elements), as in command position it's a # program-local environment setting if (/=/) { if (!$saw_non_equal) { $escape = 1; } } else { $saw_non_equal = 1; } if (m|[^\w!%+,\-./:=@^]|) { $escape = 1; } if ($escape || (!$saw_non_equal && /=/)) { # ' -> '\'' s/'/'\\''/g; # make multiple ' in a row look simpler # '\'''\'''\'' -> '"'''"' s|((?:'\\''){2,})|q{'"} . (q{'} x (length($1) / 4)) . q{"'}|ge; $_ = "'$_'"; s/^''//; s/''$//; } } continue { $ret .= "$_ "; } chop $ret; return \@err, $ret; } =item B [I]... B quotes strings so they can be passed through the shell. Each I is quoted so that the shell will pass it along as a single argument and without further interpretation. If no Is are given an empty string is returned. If any I can't be safely quoted B will B. =cut sub shell_quote { my ($rerr, $s) = _shell_quote_backend @_; if (@$rerr) { my %seen; @$rerr = grep { !$seen{$_}++ } @$rerr; my $s = join '', map { "shell_quote(): $_\n" } @$rerr; chomp $s; croak $s; } return $s; } =item B [I]... This is like B, excpet if the string can't be safely quoted it does the best it can and returns the result, instead of dying. =cut sub shell_quote_best_effort { my ($rerr, $s) = _shell_quote_backend @_; return $s; } =item B [I] B quotes the I so that it can safely be included in a shell-style comment (the current algorithm is that a sharp character is placed after any newlines in the string). This routine might be changed to accept multiple I arguments in the future. I haven't done this yet because I'm not sure if the Is should be joined with blanks ($") or nothing ($,). Cast your vote today! Be sure to justify your answer. =cut sub shell_comment_quote { return '' unless @_; unless (@_ == 1) { croak "Too many arguments to shell_comment_quote " . "(got " . @_ . " expected 1)"; } local $_ = shift; s/\n/\n#/g; return $_; } 1; __END__ =back =head1 EXAMPLES $cmd = 'fuser 2>/dev/null ' . shell_quote @files; @pids = split ' ', `$cmd`; print CFG "# Configured by: ", shell_comment_quote($ENV{LOGNAME}), "\n"; =head1 BUGS Only Bourne shell quoting is supported. I'd like to add other shells (particularly cmd.exe), but I'm not familiar with them. It would be a big help if somebody supplied the details. =head1 AUTHOR Roderick Schertler > =head1 SEE ALSO perl(1). =cut String-ShellQuote-1.04/Makefile.PL0000644000175000017500000000111111404512730017116 0ustar roderickroderick# $Id: Makefile.PL,v 1.5 2010-06-11 20:00:24 roderick Exp $ # # Copyright (c) 1997 Roderick Schertler. All rights reserved. This # program is free software; you can redistribute it and/or modify it # under the same terms as Perl itself. use ExtUtils::MakeMaker; WriteMakefile( NAME => 'String::ShellQuote', VERSION_FROM => 'ShellQuote.pm', ( $^O eq 'MSWin32' ? () : (EXE_FILES => ['shell-quote']) ), dist => { PREOP => '$(MAKE) ci', CI => 'cvs commit', RCS_LABEL => 'cvs tag v$(VERSION_SYM)', }, test => { TESTS => 'test.t' }, ); String-ShellQuote-1.04/README0000644000175000017500000000170010235654055016040 0ustar roderickroderickThis distribution contains the String::ShellQuote module, plus a command-line interface to it. It contains some functions which are useful for quoting strings which are going to pass through the shell or a shell-like object. It is useful for doing robust tool programming, particularly when dealing with files whose names contain white space or shell globbing characters. To build it, run: perl Makefile.PL make make test make install For more detailed instructions see "man perlmodinstall", "perldoc perlmodinstall", or http://www.cpan.org/modules/INSTALL.html. The documentation is embeded in the module, use perldoc ShellQuote.pm to read it before installation. Roderick Schertler Copyright (c) 1997 Roderick Schertler. All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. $Id: README,v 1.4 2005/05/03 10:53:33 roderick Exp $