strange problem with system() and backtick operator

M

Martin Kissner

hello together,

I have a very strange problem with the system() command and/or the
backtick operator.

I can not provide a small demonstration script because when I wrote the
script (see below) the very same commands worked properly.

The main script is (among other things) supposed to download files from
a ftp server and then change the file permissions of the local files to
those on the server.
I use Net::FTP for this script.

The download part works okay, but the permissions of the local files are
only changed, if the octal value is greater or equal 400.
Here is the sub which shows this strange behavior.

--- snip ---
[...]
use warnings;
use strict;
[...]

sub copy_file {
my $file = shift; # remote filepath
my $action = shift; # "0" => put; "1" => get

if ($action) {
my $lfile = strip_slash($file);
$ftp->get($file,$lfile);
my $octal = get_permissions($file,"r");
# print "`chmod $octal $lfile`\n";
# `chmod $octal $lfile`;
system("chmod $octal $lfile 2>/dev/null") == 0
or warn "\"chmod $octal $lfile\" failed!\n";
} else {
$ftp->put($lfile,$file);
}
set_l2rmtime($file);
}
--- snap ---

If I copy/paste the output from the print statement or from warn"..." to
the terminal, the chmod works.
As I said above if $octal is 400 or greater it also works!!!
If $octal is 377 or less I get:
"chmod 377 testdir/testfile.txt" failed!
If I omit the '2>/dev/null' part I get
"chmod: testdir/testlfile.txt: No such file or directory"
but only if $octal is less than 400.

I also tried working with absolute paths with the same results.
Then I wrote this little script for testing and demonstration:

--- snip ---
#!/usr/bin/perl

use warnings;
use strict;

my $octal = $ARGV[0];

# print "`chmod $octal testdir/testfile.txt`\n";
# `chmod $octal $lfile`;
system("chmod $octal testdir/testfile.txt") or warn "\"chmod $mode
testfile.txt\" failed!\n";
--- snap ---

I have testes this successfully for $octal from 0 to 777 (with backticks
and with system("...")).

At this point I have tried everything I could imagine.
Any help will be highly appreciated.

Best regards
Martin
 
J

John W. Krahn

Martin said:
I have a very strange problem with the system() command and/or the
backtick operator.

I can not provide a small demonstration script because when I wrote the
script (see below) the very same commands worked properly.

The main script is (among other things) supposed to download files from
a ftp server and then change the file permissions of the local files to
those on the server.
I use Net::FTP for this script.

The download part works okay, but the permissions of the local files are
only changed, if the octal value is greater or equal 400.
Here is the sub which shows this strange behavior.

--- snip ---
[...]
use warnings;
use strict;
[...]

sub copy_file {
my $file = shift; # remote filepath
my $action = shift; # "0" => put; "1" => get

if ($action) {
my $lfile = strip_slash($file);
$ftp->get($file,$lfile);
my $octal = get_permissions($file,"r");
# print "`chmod $octal $lfile`\n";
# `chmod $octal $lfile`;
system("chmod $octal $lfile 2>/dev/null") == 0
or warn "\"chmod $octal $lfile\" failed!\n";
} else {
$ftp->put($lfile,$file);
}
set_l2rmtime($file);
}
--- snap ---

If I copy/paste the output from the print statement or from warn"..." to
the terminal, the chmod works.
As I said above if $octal is 400 or greater it also works!!!
If $octal is 377 or less I get:
"chmod 377 testdir/testfile.txt" failed!
If I omit the '2>/dev/null' part I get
"chmod: testdir/testlfile.txt: No such file or directory"
but only if $octal is less than 400.

I also tried working with absolute paths with the same results.
Then I wrote this little script for testing and demonstration:

--- snip ---
#!/usr/bin/perl

use warnings;
use strict;

my $octal = $ARGV[0];

# print "`chmod $octal testdir/testfile.txt`\n";
# `chmod $octal $lfile`;
system("chmod $octal testdir/testfile.txt") or warn "\"chmod $mode
testfile.txt\" failed!\n";
--- snap ---

I have testes this successfully for $octal from 0 to 777 (with backticks
and with system("...")).

At this point I have tried everything I could imagine.
Any help will be highly appreciated.

Have you tried the built-in chmod function?

perldoc -f chmod



John
 
M

Martin Kissner

John W. Krahn wrote :
Have you tried the built-in chmod function?

perldoc -f chmod

Thank you for that hint.
I did not knpw that there is a built-in chmod function.
I tried it quickly and it did not quite work as expected.
I will try it more thoroughly as soon as I have time to do so.

Anyway, I did not take into account that if I try to download a file
with permission less than 400 the file will not be downloaded but an
empty file will be created.

Nevertheless I'd be interessted, why my chmod command fails if the file
exists.

Thanks in advance
Martin
 
T

Tad McClellan

Martin Kissner said:
John W. Krahn wrote :

I tried it quickly and it did not quite work as expected.


Are you writing the permissions in octal (with a leading zero)?

Nevertheless I'd be interessted, why my chmod command fails if the file
exists.


It fails because you are doing something wrong.

We don't know what it is that you are doing, because you
have not shown us your code...
 
M

Martin Kissner

Tad McClellan wrote :
Are you writing the permissions in octal (with a leading zero)?

I was writing
chmod oct($octal), $local_file
as suggested in perldoc -f chmod.
It fails because you are doing something wrong.

We don't know what it is that you are doing, because you
have not shown us your code...
Well, I've been showing plenty of code in my first posting.
I don't want to post the whole script because it is quite long and I
don't want to bother.

I guess the `chmod ...` fails, because the ftp connection is still open
and the file did not really download successfully. I think so because I
can easyly chmod when the scipt has finished and the connection is
closed.

Can anyone confirm this assumption?

Regards
Martin
 
A

A. Sinan Unur

Tad McClellan wrote :

I was writing
chmod oct($octal), $local_file
as suggested in perldoc -f chmod.

Let's see:

$mode = '0644'; chmod oct($mode), 'foo'; # this is better
$mode = 0644; chmod $mode, 'foo'; # this is best

Why not use the best method?

Sinan
 
M

Martin Kissner

A. Sinan Unur wrote :
Let's see:

$mode = '0644'; chmod oct($mode), 'foo'; # this is better
$mode = 0644; chmod $mode, 'foo'; # this is best

Why not use the best method?

Hello Sinan,

I used oct($mode) because I get $mode from a sub which returns a three
(or less) digit decimal number. The number is parsed and calculated from
a ftp directory listing.

I asumed that the last method is best, because $mode is initialized
allready with an octal value.
If I have a decimal value I thought I'd have to convert it to octal.

If I am wrong or if there is a better method to do so, please let me
know.

Regards
Martin
 
A

A. Sinan Unur

A. Sinan Unur wrote :


Hello Sinan,

I used oct($mode) because I get $mode from a sub which returns a three
(or less) digit decimal number. The number is parsed and calculated
from a ftp directory listing.

I asumed that the last method is best, because $mode is initialized
allready with an octal value. If I have a decimal value I thought I'd
have to convert it to octal.

perldoc -f oct

oct EXPR
oct Interprets EXPR as an octal string and returns the
corresponding value.

Notice the "octal string".

A number is just a number, that is it.

#!/usr/bin/perl

use strict;
use warnings;

my $x = 64;
my $y = 0100;
my $z = '0100';

print "x = $x", "\n";
print 'oct(x) = ', oct($x), "\n";

print "y = $y\n";
print 'oct(y) = ', oct($y), "\n";

print "z = $z\n";
print 'oct(z) = ', oct($z), "\n";

Sinan
 
M

Martin Kissner

A. Sinan Unur wrote :
perldoc -f oct

oct EXPR
oct Interprets EXPR as an octal string and returns the
corresponding value.

Notice the "octal string".

A number is just a number, that is it.
[script sniped]

Thank you for your help.
This clarifies a lot.

If I understand right, I should use "chmod oct($mode), 'file'" (like I
did ;-)) if $mode is the result of an addition (and not an octal value).

perldoc -f oct
...
The oct() function is commonly used when a string such as 644
needs to be converted into a file mode, for example.

I also had some more time to look at my first problem.
Actually the file is not created by "$ftp->get()" when it is not readable on
the server (this was unexpected anyway).

I myself create the file later in the script with "`touch -t ....`"
because I want to set the modtime of the downloaded file to the modtime
of the file on the server.
After realizing this the solution was simple (using "and").

btw: is there a built-in function to manipulate modification time of
files in Perl?

Regards
Martin
 
T

Tad McClellan

Martin Kissner said:
A. Sinan Unur wrote : ^^^^^^
^^^^^^ ^^^^^^
^^^^^^
Thank you for your help.
This clarifies a lot.


But you don't "have it" yet, so let's keep trying...

There is an abstract concept called a "number".

There are many _representations_ for any particular "number".

Let's use the number "ten" for example:

1010 ( 2)
12 ( 8)
10 (10)
0A (16)
8 + 2
11 - 1


All of those representations correspond to the *same number*, they
are just different ways of writing the same thing.
If I understand right, I should use "chmod oct($mode), 'file'" (like I
did ;-)) if $mode is the result of an addition


No!

You should use "chmod oct($mode) when $mode is a *string*
(not when it is a number).

(and not an octal value).


There is no such thing as an "octal value".

There could be a number that is represented in octal (base 8) though.

I don't think you understand Perl's data types well enough yet,
have a look at the "Scalar values" section in:

perldoc perldata

A scalar may contain one single value in any of three
different flavors: a number, a string, or a reference.


You need to be able to understand which one you've got if you
hope to process it correctly (sans DWIMery).
 
M

Martin Kissner

Tad McClellan wrote :
Martin Kissner wrote:

But you don't "have it" yet, so let's keep trying...

Thank you for your help, I really appreciate it.
There is an abstract concept called a "number".

[...]

All of those representations correspond to the *same number*, they
are just different ways of writing the same thing.

Okay, so the "number" ten (1010b, 012, 10 0xA) is "the number of my fingers".
No!

You should use "chmod oct($mode) when $mode is a *string*
(not when it is a number).



There is no such thing as an "octal value".

There could be a number that is represented in octal (base 8) though.

I think I understand.
The question is:
What is the best way to use chmod if i have a number that is represented
in decimal (i.e. 644) but I need a number represented in octal with
identical digits (0644).

--- aaahhhh ---
While writing this, I think I really get it.
If I want to use chmod with a number and I can only produce the decimal
representation I need to use the decimal representation of 0644 which is
420.

I only have to change one line within a loop in my sub which parses
the first column of the ftp directory listing and returns a _number_
"$multiplier *= 8;" instead of "$multiplier *= 10;"

Thanks again.
This made my day.

Best regards
Martin
 
M

Martin Kissner

John W. Krahn wrote :
perldoc -f utime

Thank you for this hint.
Right now I am travelling. I'll check this out as soon as I am back
home.

Best regards
Martin
 
D

Dr.Ruud

Martin Kissner:
What is the best way to use chmod if i have a number that is
represented in decimal (i.e. 644)

That is not a decimal but an octal representation. It just doesn't have
the signs that it is an octal representation. Where do you get this
number from? Treat it as a string and use oct().

but I need a number represented in octal with
identical digits (0644).

$val = oct('644'); # $val is now the numeric value 420 (decimal)

printf "%#o\n", $val; # should print 0644
 
T

Tad McClellan

Martin Kissner said:
Tad McClellan wrote :

Thank you for your help, I really appreciate it.

I think I understand.


Not yet...
The question is:
What is the best way to use chmod if i have a number that is represented
in decimal (i.e. 644) but I need a number represented in octal with
identical digits (0644).


Then what you need is a *different* number.

--- aaahhhh ---
While writing this, I think I really get it.
If I want to use chmod with a number and I can only produce the decimal
representation I need to use the decimal representation of 0644 which is
420.


Ding ding ding! We have a winner! :)
 
M

Martin Kissner

Dr.Ruud wrote :
Martin Kissner:

$val = oct('644'); # $val is now the numeric value 420 (decimal)

printf "%#o\n", $val; # should print 0644

This is what I did first, but I think it's more elegant to calculate the
number which is needed to chmod to the desired permissions than to
calculate a number, convert ist to a string and then convert it to the
number which is needed.

Nevertheless, thank's for your feedback.

Best regards
Martin
 
D

Dr.Ruud

Martin Kissner:
Dr.Ruud:

This is what I did first, but I think it's more elegant to calculate
the number which is needed to chmod to the desired permissions than to
calculate a number, convert ist to a string and then convert it to the
number which is needed.

It was not meant as code to use, I just tried to explain to you some of
the differences between value and representation.
 

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

No members online now.

Forum statistics

Threads
473,787
Messages
2,569,630
Members
45,335
Latest member
Tommiesal

Latest Threads

Top