strings with formatted characters in %ARGV

M

mfrost8

I thought I knew perl pretty well, but then this came up and has me
totally stumped -- making me realize I don't understand it as well as
I thought...

I'm trying to pass one or more formatted (i.e. with '\n' in it)
strings to a perl program and have them print with the formatting.
Consider the following perl code:

#!/usr/bin/perl
print $ARGV[0];

Now if I run the program as follows:

$ ./x.pl "FOO\n\n\n"

I get

FOO\n\n\n$

which I don't understand. If I set a scalar string within the program
similarly:

#!/usr/bin/perl
my $foo = "FOO\n\n\n";
print $foo;

I get what I'd expect.

What am I missing here? Why can't I get print/printf to honor those
special characters when used from the command line?

Thanks
 
A

anno4000

I thought I knew perl pretty well, but then this came up and has me
totally stumped -- making me realize I don't understand it as well as
I thought...

I'm trying to pass one or more formatted (i.e. with '\n' in it)
strings to a perl program and have them print with the formatting.
Consider the following perl code:

#!/usr/bin/perl
print $ARGV[0];

Now if I run the program as follows:

$ ./x.pl "FOO\n\n\n"

I get

FOO\n\n\n$

This is discussed in the FAQ "How can I expand variables in text strings?".
While you want to expand escape sequences and not variables, the reason
for the behavior and the solutions are similar.

Anno
 
J

Jürgen Exner

I'm trying to pass one or more formatted (i.e. with '\n' in it)
strings to a perl program and have them print with the formatting.

'\n' has nothing to do with formatting. It is a representation of a
character, that otherwise could not by typed.
Now if I run the program as follows:
$ ./x.pl "FOO\n\n\n"

I get
FOO\n\n\n$

which I don't understand. If I set a scalar string within the program
similarly:
my $foo = "FOO\n\n\n";
print $foo;

I get what I'd expect.

What am I missing here? Why can't I get print/printf to honor those
special characters when used from the command line?

You are confusing program text and data.
my $foo = "FOO\n\n\n";
is program source code. When interpreted the Perl interpreter will convert
this into the text FOO followed by three newlines in whatever representation
is needed for your OS AND THEN STORE THIS DATA ITEM. This happens as compile
time.

However when reading parameters from the command line Perl reads that data
as is because it is data already, no need to interpret it.

By a similar argument you could ask why
./x.pl "print 'Hello world'"
doesn't print the text Hello World.

jue
 
M

mfrost8

'\n' has nothing to do with formatting. It is a representation of a
character, that otherwise could not by typed.






You are confusing program text and data.
my $foo = "FOO\n\n\n";
is program source code. When interpreted the Perl interpreter will convert
this into the text FOO followed by three newlines in whatever representation
is needed for your OS AND THEN STORE THIS DATA ITEM. This happens as compile
time.

However when reading parameters from the command line Perl reads that data
as is because it is data already, no need to interpret it.

By a similar argument you could ask why
./x.pl "print 'Hello world'"
doesn't print the text Hello World.

jue

Huh. Interesting. I guess I got burned here by how perl usually
understands what you want to do without having to explicitly specify
it.

I could see this in the case of variables in a string -- how would
perl know what "$foo" is? But I would have thought that
representations of special characters like '\n' would be treated
differently.

My assumption here would be that when running using a function like
print that kind of assumes it's working with strings that it would
interpret that 2-character sequence when it was invoked.

So then this means that I have to parse out all the 2-character
sequences myself and replace them? I read the FAQ entry that the
previous poster sent and it seemed to use a regex to do substitutions
on the string which then replaced the same string with itself. I
didn't have much success bending that FAQ to do my bidding. I tried a
few things, but the last thing I tried was simply

my $foo = $ARGV[0];
$foo =~ s/(\\n)/$1/g;
print $foo;

Which didn't seem to change anything.

What do I need to do to make this work the way I expect it to?

Thanks very much for your time and input.
 
M

mfrost8

I tried a
few things, but the last thing I tried was simply

my $foo = $ARGV[0];
$foo =~ s/(\\n)/$1/g;
print $foo;

Which didn't seem to change anything.

What do I need to do to make this work the way I expect it to?

Thanks very much for your time and input.

Whoops. I meant to say that I'd tried

my $foo = $ARGV[0];
eval { $foo =~ s/(\\n)/$1/eeg };
print $foo;

and that didn't yield anything different.

Thanks
 
M

Michele Dondi

Subject: strings with formatted characters in %ARGV

Nope, there's nothing useful in the hash slot of *ARGV that I know of.
I'm trying to pass one or more formatted (i.e. with '\n' in it)
strings to a perl program and have them print with the formatting.

It's not "formatted". It just contains "\n"s. (Not '\n's, BTW, at
least when speaking Perl.)

Consider the following perl code:

#!/usr/bin/perl
print $ARGV[0];

Now if I run the program as follows:

$ ./x.pl "FOO\n\n\n"

I get

FOO\n\n\n$

That's to be expected. That's what the *shell* is giving to your Perl
program. You have to ask the shell to pass in real newlines, as
opposed to whatever else:

kirk:~ [22:08:08]$ perl -le 'print $ARGV[0]' 'FOO
FOO



kirk:~ [22:08:32]$
which I don't understand. If I set a scalar string within the program ^^^^^^
^^^^^^

similarly:

#!/usr/bin/perl
my $foo = "FOO\n\n\n";
print $foo;

I get what I'd expect.

You SAID it. If you set it *within* the program, then you have the
perl interpreter handle the thing otherwise you let the shell do so.
What am I missing here? Why can't I get print/printf to honor those
special characters when used from the command line?

Do you want to pass a literal '\n\n\n' and have Perl interpret it as
if it were "\n\n\n\"? The roll your own quoted stuff expansion routine
or -if you're brave enough- use string eval: be prepared to be open to
all sorts of security risks if doing so, though.


Michele
 
M

Michele Dondi

I could see this in the case of variables in a string -- how would
perl know what "$foo" is? But I would have thought that
representations of special characters like '\n' would be treated
differently.

The rationale is that one wants to do so rarely enough that it'd
better *not* be the default and that there's an easy enough way to do
so when needed.
So then this means that I have to parse out all the 2-character
sequences myself and replace them? I read the FAQ entry that the
previous poster sent and it seemed to use a regex to do substitutions
on the string which then replaced the same string with itself. I

With an /ee modifier. But it is string eval, and thus evil(TM).
Fortunately ou don't need it yourself...
didn't have much success bending that FAQ to do my bidding. I tried a
few things, but the last thing I tried was simply

my $foo =3D $ARGV[0];
$foo =3D~ s/(\\n)/$1/g;

Try

$foo =~ s/\\n/\n/g;

(No need to capture)
print $foo;

Which didn't seem to change anything.

In fact you substituted what you matched with... er... well... itself!


Michele
 
T

Tad McClellan

A fundamental tenant of computer science, namely the difference
between what is "code" and what is "data".

"code" and "data" are treated differently.

Perl source is "code" while command line arguments are "data".



Because those 2 characters are NOT special in "data".



Oh. Jürgen has already pointed out what you are missing here. :)


I would have thought that
representations of special characters like '\n' would be treated
differently.


If they are in "data", then they are not "special".

My assumption here would be that when running using a function like
print that kind of assumes it's working with strings


print 10;

no string there (until perl makes it into one).

that it would
interpret that 2-character sequence when it was invoked.


Interpreting backslash escapes such as \n is not related to
print, or any other, function.

Interpreting backslash escapes is related to double quoted
strings in "code".

So then this means that I have to parse out all the 2-character
sequences myself and replace them?

Yes.


I read the FAQ entry that the
previous poster sent and it seemed to use a regex to do substitutions
on the string which then replaced the same string with itself. I
didn't have much success bending that FAQ to do my bidding. I tried a
few things, but the last thing I tried was simply

my $foo = $ARGV[0];
$foo =~ s/(\\n)/$1/g;
print $foo;

Which didn't seem to change anything.


It changed it to be what it already was.

What do I need to do to make this work the way I expect it to?


$foo =~ s/\\n/\n/g;
 
T

Tad McClellan

On Jun 25, 2:51 pm, (e-mail address removed) wrote:
Whoops. I meant to say that I'd tried

my $foo = $ARGV[0];
eval { $foo =~ s/(\\n)/$1/eeg };
print $foo;

and that didn't yield anything different.


Let's analyse how that happened.

The first 'e' has this code to evaluate:

$1

so it replaces the variable name with the variable's value, leaving
this for the second 'e' to evaluate:

\n

That is a bareword string, it evaluates to itself.

Then the outer eval sees a 3 (the return value from s/// is the
number of substitutions it did), and so is useless here.
 
M

mfrost8

$foo =~ s/\\n/\n/g;

Thanks much for the many responses I received. I genuinely appreciate
you folks taking the time time help me out with this.

After my last post, I played around some more and came up with the
code shown above that I had found worked as well. However, what I was
hoping for was something more general purpose that allowed me to
replace all or at least multiple metacharacters in one go. I'm not
quite able to come up with something that will work here. I've tried

$foo =~ s/(\\[nrt])/$1/eeg;

which yields a bunch of

Use of uninitialized value in substitution iterator at ...

lines. It appears to me that I'm not making a match there, but I'm
not sure why. If it's data, then perl should just see '\t' as 2
characters.

In this case, I'm wondering if I need the eval's in the regex. If I
drop them, however, I don't get the errors, but I get the same output
repeated (i.e. no substitutions).

Mark
 
C

Clenna Lumina

$foo =~ s/\\n/\n/g;

Thanks much for the many responses I received. I genuinely appreciate
you folks taking the time time help me out with this.

After my last post, I played around some more and came up with the
code shown above that I had found worked as well. However, what I was
hoping for was something more general purpose that allowed me to
replace all or at least multiple metacharacters in one go. I'm not
quite able to come up with something that will work here. I've tried

$foo =~ s/(\\[nrt])/$1/eeg;

which yields a bunch of

Use of uninitialized value in substitution iterator at ...

If you really want to do it that way, something like the following
should work:

#!/usr/bin/perl

use strict;

my $foo = join (' ', @ARGV);

$foo =~ s/\\([nrt])/"qq{\\$1}"/gee;

print qq{"$foo"\n};

__END__


__OUTPUT__
./foo.pl '1 2\n3'
"1 2
3"

Note, I noticed that if I passed the arguements without any quoting
(./foo.pl 1 2\n3) the "\" would get stripped (I'm guessing my the
shell - linux, bash) so perl only sees '1 2n3'... why does the slash get
stripped?
 
T

Tad McClellan

[ it is bad form to quote .sigs (unless you are commenting on the .sig)]
However, what I was
hoping for was something more general purpose that allowed me to
replace all or at least multiple metacharacters in one go. I'm not
quite able to come up with something that will work here.


I'd list the chars to be translated in a hash, and then look
them up in the s///


-----------------
#!/usr/bin/perl
use warnings;
use strict;

my %chars = (
n => "\n",
r => "\r",
t => "\t",
);
my $foo = 'foo\tbar\nbaz\n';

$foo =~ s/\\([nrt])/$chars{$1}/g;

print $foo;
 
M

Michele Dondi

Note, I noticed that if I passed the arguements without any quoting
(./foo.pl 1 2\n3) the "\" would get stripped (I'm guessing my the
shell - linux, bash) so perl only sees '1 2n3'... why does the slash get

Yes, it's the shell.
stripped?

Because the shell does so. It has it's own backslash quoting, e.g. to
quote a bare single quote. But it doesn't handle special charachters.
We have to live with that. Period.


Michele
 
C

Clenna Lumina

Michele said:
Yes, it's the shell.


Because the shell does so. It has it's own backslash quoting, e.g. to
quote a bare single quote. But it doesn't handle special charachters.
We have to live with that.

I had some how forgot the shell handles foward slashes like that. It
seems youy can simply escape them too as an alternative to quoting
(./foo.pl 1 2\\n3), if one really wanted to.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,994
Messages
2,570,223
Members
46,814
Latest member
SpicetreeDigital

Latest Threads

Top