Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical
 
PerlMonks  

passing delimiters on command line

by Anonymous Monk
on Sep 13, 2004 at 09:28 UTC ( [id://390519]=perlquestion: print w/replies, xml ) Need Help??

Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Hello Monks,

I am trying to pass a delimiter string via a command line argument like this :
./script.pl "\t" ARG1 ARG2
so inside the script I would like to set the $" to do some interpolation on a list like this :
my $delim = shift @ARGV; $" = $delim; ... print "@list";
but with any of the backslashed characters what prints is something like this :
list_item1\tlist_item2\tlist_item3
and not what I am going for which is to have the line print tab-delimited, in this case :
list_item1 list_item2 list_item3
I don't understand why this happens because if I set the delimiter in the script like this :
$" = "\t"
everything is fine. I have tried every kind of escaping or quoting I can think of and nothing seems to work.

Replies are listed 'Best First'.
Re: passing delimiters on command line
by Joost (Canon) on Sep 13, 2004 at 09:54 UTC
    The problem here is that "\t" is not interpreted by the shell to be a tab character, but just a regular backslash followed by a "t":

    > echo "\t" \t

    Perl also doesn't interpret this input as a tab, because that would make it impossible to have strings with a literal "\t" sequence. \escape sequences are only interpreted in double quoted string literals (and regular expressions).

    The way to pass special characters in bash is to use $'\code', ie $'\t' for tab:

    > perl -e '$"=shift;print "@ARGV"' $'\t' a b c d e a b c d e

    If you use another shell, look in its documentation.

    Ofcourse you could also do $" = eval '"'.shift(@ARGV).'"'; but that would complicate matters if anyone needs to pass something that can't be put in double quotes.

    update: fixed typo

Re: passing delimiters on command line
by ikegami (Patriarch) on Sep 13, 2004 at 09:52 UTC

    If you trust the user,
    $" = eval '"' . $delim . '"'; works.
    Use eval with extreme caution, for security reasons.

    You could parse it yourself:
    %lookup_slash = ( t => "\t", n => "\n", ... );
    $delim =~ s/\\(.)/$lookup_slash{$1}/ge;

    But do you really expect slashed delimiters other than "\t"? If not, the previous snippet can be simplified to:
    $delim =~ s/\\t/\t/g;

    Or you could go fancier args...

      The basic problem with  $" = eval '"' . $delim . '"' is that someone can pass something like  `rm -rf /` as the delimiter argument to your script. A QND workaround would be to just reject anything over two characters in length for the delimiter argument... like so:
      die "some trouble is brewing\n" if length($ARGV[0]) > 2; # Freely borrowed from ikegami $delim = eval '"' . $ARGV[0] . '"'; print "Field1" . $delim . "Field2" . $delim . "Field3" . $/;
      Good luck
Re: passing delimiters on command line
by thor (Priest) on Sep 13, 2004 at 10:55 UTC
    On Unix, you can bypass the shell's tab-completion (if it has it) by hitting Ctrl-v before hitting the tab. This will give you a literal tab character that should be recognized by perl. The same thing will work for literal newlines and escapes, too.

    thor

    Feel the white light, the light within
    Be your own disciple, fan the sparks of will
    For all of us waiting, your kingdom will come

Re: passing delimiters on command line
by Crian (Curate) on Sep 13, 2004 at 09:32 UTC
    I use to pass a tab (or other) delimiter to a Perl script too. There I give the delimiter as the last parameter and don't escape it at all (it works at least under Win2k).

    The output is delimited by tabs as I wanted it.

    Perhaps the difference is, that I don't use $" = "\t", I print out the delimiter I got from the user between each data "per hand" in the print statement, as print $data1, $delimiter, $data2, $delimiter, ..., $datan, "\n";.

    If you want to put the delimiter into $", you could use sprintf to print it into that variable. That may be safer than eval.
Re: passing delimiters on command line
by BrowserUk (Patriarch) on Sep 13, 2004 at 09:57 UTC

    As a one-liner:

    >perl -wle"${\"} = eval qq[\"$ARGV[0]\"]; my @a = 1 .. 10; print \"@a\ +"" \t 1 2 3 4 5 6 7 8 9 + 10

    Or more simply in a program:

    #! perl -slw use strict; $" = eval qq["$ARGV[ 0 ]"]; my @a = 1 .. 10; print "@a"; __END__ P:\test>test.pl \t 1 2 3 4 5 6 7 8 9 + 10

    Caveat: If you type in a dangerous command in place of the delimiter, it will do dangerous things!

    Update: As a less dangeruos alternative you could do one of:

    >perl -wle"${\"} = chr $ARGV[0]; my @a = 1 .. 10; print qq[@a]" 9 1 2 3 4 5 6 7 8 9 + 10 >perl -wle"${\"} = chr hex $ARGV[0]; my @a = 1 .. 10; print qq[@a]" 0x +9 1 2 3 4 5 6 7 8 9 + 10 >perl -wle"${\"} = chr oct $ARGV[0]; my @a = 1 .. 10; print qq[@a]" 11 1 2 3 4 5 6 7 8 9 + 10

    Examine what is said, not who speaks.
    "Efficiency is intelligent laziness." -David Dunham
    "Think for yourself!" - Abigail
    "Memory, processor, disk in that order on the hardware side. Algorithm, algorithm, algorithm on the code side." - tachyon
Re: passing delimiters on command line
by Anonymous Monk on Sep 13, 2004 at 13:34 UTC
    ./script.pl \^V^I ARG1 ARG2
    If you have a shell where in interactive mode tab means something special (like in bash), you need to escape the tab *twice*. First to take the tab as-is - this is done by typing a CNTL-V character before the tab. Then you need to tell the parser that it should take the tab as a symbol, and not as whitespace separating the symbols. This can be done by putting a backslash in front of it - or by putting it inside quotes.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://390519]
Approved by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others lurking in the Monastery: (3)
As of 2024-04-23 06:00 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found