ls -al "file 1" "file'2" ; cat /etc/passwd
####
ls '-al' 'file 1' 'file'\''2' ';' 'cat' '/etc/passwd'
####
#!/usr/bin/perl
# used http://www.cs.hmc.edu/courses/2003/spring/cs60/fsm.pdf
# to transform state machine into regexp
$cmd=<>;
$arg="";
chomp $cmd;
$cmd.=" ";
# regexp
# ( |([^'"\\ ]+)|(\\.)|("(([^"\\])|(\\.))*")|('[^']*'))
# only global matching
# ( |(?:[^'"\\ ]+)|(?:\\.)|(?:"(?:(?:[^"\\])|(?:\\.))*")|(?:'[^']*'))
# we need to do second subst to remove " and ' pairs and unescape \ so need some flags
# ( |(?:[^'"\\ ]+)|(\\.)|("(?:(?:[^"\\])|(\\.))*")|('[^']*'))
while($cmd=~s/^( |(?:[^'"\\ ]+)|(\\.)|("(?:(?:[^"\\])|(\\.))*")|('[^']*'))(.*)$/$6/)
{
$c=$1;
# the flags...
$esc=$2;
$dquote=$3;
$dquoteEsc=$4;
$squote=$5;
print "c=$c arg=$arg cmd=$cmd esc=$esc dquote=$dquote dquoteEsc=$dquoteEsc squote=$squote\n";
if($c eq " ")
{
$arg=~s/'/'\\''/g; # shell escape the '
$res .= "'$arg' ";
$arg="";
next;
}
if(($esc ne "")|($dquoteEsc ne "")) { $c=~s/\\//g }
if($dquote ne "") { $c =~ s/^"(.*)"$/$1/}
if($squote ne "") { $c =~ s/^'(.*)'$/$1/}
$arg .= $c;
}
print "$res\n";