Hi Monks!
My Perl utility generates a bash script that consists of mkdir/rsync/cp commands.
This bash script is later used by users (this means that I don't want to actually run those commands when my utility runs, rather just to generate the script).
Given a UNIX path, I need to do two different actions - depending on the path type (dir or file):
1. If the path is a directory, then just create it using mkdir.
2. If the path is a file, then just copy the file from the dir directory using rsync or cp (depending if user specified a machine to copy from).
For example, consider this:
touch /a/b/c/d1
In that case, the bash script will look like:
mkdir -p /tmp/a/b/c cp /a/b/c/d1 /tmp/a/b/c # Or: rsync -a $USER@MACHINE:/a/b/c/d1 /tmp/a/b/c
The utility works good, unless a path contains "special chars".
I tried to deal with it by escaping and using quotes but I can't seem to cover all cases.
By "special chars" I mean chars like ":",";","(",")","_",....
I tried to use the following to subs:
sub escape { my ($path) = @_; if ($path =~ /\\/) { $path =~ s/\\/\\\\/g; } if ($path =~ /\$/) { $path =~ s/\$/\\\$/g; } return $path; } sub wrap_with_quotes { my ($path) = @_; if ($path =~ /( |\;|\!)/) { return '"'.$path.'"'; } return $path; }
I also tried to use quotemeta:
sub escape { my ($path) = @_; my $new_path = quotemeta($path); $new_path =~ s/\\\//\//g; return $new_path; }
But it also failed for a lot of cases and it escaped alot of unneeded chars (like ".", "/", etc. - which are valid in paths without escaping).
The code looks like:
foreach my $dir (sort(keys(%dirs))) { $dir = escape($dir); $dir = wrap_with_quotes($dir); print("mkdir -p /tmp/$dir\n"); } foreach my $file (sort(keys(%files))) { my $parent_dir = dirname($file); my $abs_path = abs_path($file); $abs_path = escape($abs_path); $abs_path = wrap_with_quotes($abs_path); $parent_dir = escape($parent_dir); $parent_dir = wrap_with_quotes($parent_dir); print("cp $abs_path /tmp/$parent_dir\n"); } foreach my $file (sort(keys(%remote_files))) { my $parent_dir = dirname($file); my $abs_path = abs_path($file); my $host = get_host(); $abs_path = escape($abs_path); $abs_path = wrap_with_quotes($abs_path); $parent_dir = escape($parent_dir); $parent_dir = wrap_with_quotes($parent_dir); print("rsync -a $host$abs_path /tmp/$parent_dir\n"); }
I of course want to support any kind of path. For example, the special char could contain a "\" before it, and then I need to escape both of them. I built a small test for you to understand what I'm after:
declare -a special_chars=("!" "@" "#" "$" "%" "^" "_" "-" "=" "+" "[" +"]" "(" ")" "{" "}" "'" ":" "," "." ";" " " "\"" "<" ">") if [ "$1" == 1 ]; then # create playground (before running the bash sc +ript) for special_char in "${special_chars[@]}"; do mkdir -p "/test1/a${special_char}b" touch "/test1/a${special_char}b/data" done else # test playground output (after running the bash script) for special_char in "${special_chars[@]}"; do mkdir -p "/tmp/test1/a${special_char}b" if [ "$?" -ne 0 ]; then exit 1 fi done fi
If 1 is passed to the script, it will generate directory with one special char (for example: test1/a;b).
Then I run the generated bash script and then the test script again - if 0 is passed, it will check if the bash script successfully created dirs & copied files into /tmp.
Hope it makes sense.
I also noticed that rsync and cp except different escaping. For example, "/test1/a;b/data" works for cp and "/test1/a\;b/data" works for rsync.
Is there an easy way to handle special chars in path? All I want is to create mkdir/cp/rsync commands in a bash script that so they will later work.
Please help me to fix the wrap_with_quotes and escape subs or find a better way.

In reply to Escape special chars in a path by ovedpo15

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.