Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

UNIX commands: chmod

6 views
Skip to first unread message

Gabor Szabo

unread,
Mar 25, 2006, 5:58:30 AM3/25/06
to perl6-l...@perl.org
Hmm, I don't really know how to do this but Gaal told me to
write up some proposal here.

So we had chmod in Perl5, I would like to make sure it works in
Perl6 as well with slight modifications.

LIST = chmod MODE, LIST

1) In list context it would return the names of the files successfully
changed .
In scalar context it should be the number of files successfully changed
as it is in Perl5
2) In addition to the octet representation it would also be ready to receive
the unix style mode representation which is string
one or more of the letters ugoa,
one of the symbols +-=
one or more of the letters rwxXstugo

3) While some of the modes are UNIX specific, it would be nice to find similar
modes in other operating system and do the right thing there too.
e.g. "all" in UNIX would map to "Everyone" in Windows/NTFS

4) "filename".chmod(MODE) should also work and I guess
<file1 file2 file3>.chmod(MODE) should also work on those 3 files


I committed a test file t/builtins/system/chmod.t
but we really need the built in stat() function in order to test this.

Gabor

Nicholas Clark

unread,
Mar 25, 2006, 6:06:11 AM3/25/06
to Gabor Szabo, perl6-l...@perl.org
On Sat, Mar 25, 2006 at 12:58:30PM +0200, Gabor Szabo wrote:
> 4) "filename".chmod(MODE) should also work and I guess
> <file1 file2 file3>.chmod(MODE) should also work on those 3 files

That seems to be implying a chmod method on all strings, and all lists.
Assuming chmod doesn't get special favours, how many methods would it need
to implement all the existing builtins like this?

Nicholas Clark

Gabor Szabo

unread,
Mar 25, 2006, 6:22:18 AM3/25/06
to perl6-l...@perl.org

Not that I understand the problem here but "filename".slurp seems to work.
Did it get special favour?

Gabor

Damian Conway

unread,
Mar 25, 2006, 6:24:18 PM3/25/06
to Gabor Szabo, perl6-l...@perl.org
Gabor Szabo wrote:

> Hmm, I don't really know how to do this but Gaal told me to
> write up some proposal here.
>
> So we had chmod in Perl5, I would like to make sure it works in
> Perl6 as well with slight modifications.
>
> LIST = chmod MODE, LIST
>
> 1) In list context it would return the names of the files successfully
> changed .
> In scalar context it should be the number of files successfully changed
> as it is in Perl5

One might argue that it would be more useful to return a result object whose
boolean value is the success or failure, whose numeric and string values are
the number of files *un*changed, and whose list value is the list of those
*un*changed files.

Then you could write:

unless chmod 0o664, @files -> $failed {
warn "Couldn't change the following $failed file(s): $failed[]";
}

See below for a partial Perl 5 implementation.

BTW, I think that *many* of Perl 6's list-taking builtins could conform to the
same (or to a very similar) general interface.


> 2) In addition to the octet representation it would also be ready to receive
> the unix style mode representation which is string
> one or more of the letters ugoa,
> one of the symbols +-=
> one or more of the letters rwxXstugo

I like this for documentation readability.


> 3) While some of the modes are UNIX specific, it would be nice to find similar
> modes in other operating system and do the right thing there too.
> e.g. "all" in UNIX would map to "Everyone" in Windows/NTFS

I like this for portability.


> 4) "filename".chmod(MODE) should also work and I guess
> <file1 file2 file3>.chmod(MODE) should also work on those 3 files

I think this is not a good idea (as per Nicholas's previous comment),
especially given that you can already write those:

"filename" ==> chmod(MODE)
<file1 file2 file3> ==> chmod(MODE)

if you want the filenames out front.

Damian

-----cut----------cut----------cut----------cut----------cut-----

Partial Perl 5 implementation:

sub chmod {
my ($mode, @files) = @_;

$mode = _normalize_mode($mode);

my @failed;
FILE:
for my $file (@files) {
next FILE if chmod $mode, $file;
push @failed, $file;
}

use Contextual::Return;
return
BOOL { !@failed }
SCALAR { 0+@failed }
LIST { @failed }
}

sub _normalize_mode {
return shift @_; # Extra smarts needed here ;-)
}

unless (my $failed = &chmod(0664, qw(test1 test2 test5))) {
warn "Failed to chmod $failed file(s): @$failed";
}

Jonathan Lang

unread,
Mar 25, 2006, 8:30:51 PM3/25/06
to dam...@conway.org, Gabor Szabo, perl6-l...@perl.org
Damian Conway wrote:
> One might argue that it would be more useful to return a result object whose
> boolean value is the success or failure, whose numeric and string values are
> the number of files *un*changed, and whose list value is the list of those
> *un*changed files.
>
> Then you could write:
>
> unless chmod 0o664, @files -> $failed {
> warn "Couldn't change the following $failed file(s): $failed[]";
> }
>
> See below for a partial Perl 5 implementation.
>
> BTW, I think that *many* of Perl 6's list-taking builtins could conform to the
> same (or to a very similar) general interface.

The biggest problem that I have with this is that you devalue the
sigils: it becomes the accepted norm that $failed is nearly as likely
to contain a list-like object as a scalar-like object.

How important is it that perl 6 maintains the notion that $foo and
@foo are entirely different things? If it isn't that important, the
above could be rewritten as

unless chmod 0o664, @files -> $failed {

warn "Couldn't change the following $failed file(s): @failed";
}

...with the choice of sigil determining whether the object gets
treated as a scalar or as a list.

Also, there's the matter of "unneccessary paperwork": if the only
thing that I use the return value for is a boolean test, then all of
the effort involved in loading the filenames into a list was wasted
effort. Is there a way that the "lazy evaluation" concept could be
extended to function return values? Something like:

> Partial Perl 5 implementation:
>
> sub chmod {
> my ($mode, @files) = @_;
>
> $mode = _normalize_mode($mode);
>
> my @failed;
> FILE:
> for my $file (@files) {
> next FILE if chmod $mode, $file;
> push @failed, $file;
> }
>
> use Contextual::Return;

# at this point, have the sub temporarily suspend operation.

> return
> BOOL { !@failed }
> SCALAR { 0+@failed }
> LIST { @failed }
> }
>
> sub _normalize_mode {
> return shift @_; # Extra smarts needed here ;-)
> }
>
> unless (my $failed = &chmod(0664, qw(test1 test2 test5))) {
> warn "Failed to chmod $failed file(s): @$failed";
> }

...$failed is evaluated in boolean context; so the chmod sub resumes
operation, determines the boolean value, and suspends operation again,
because neither LIST nor SCALAR has been evaluated.

...when $failed is evaluated in scalar context, the chmod sub resumes
operation, determines the scalar value, and suspends operation again,
because LIST still hasn't been evaluated.

...when $failed is evaluated in list context, the chmod sub resumes
operation, determines the list value, and closes out, because all
three of BOOL, SCALAR, and LIST have now been evaluated.

Meanwhile,

die unless chmod(0664, qw(test1 test2 test5));

...the anonymous return value is evaluated in boolean context; so
chmod resumes operation, determines the boolean value, and suspends
operation again.

...the anonymous return value goes out of scope, so the suspended
chmod sub gets discarded along with it.

Or have some compiler optimization which checks the contexts that the
return value gets used in, and only returns values for those contexts.

--
Jonathan "Dataweaver" Lang

Mark Overmeer

unread,
Mar 26, 2006, 1:39:31 PM3/26/06
to Gabor Szabo, perl6-l...@perl.org
* Gabor Szabo (sza...@gmail.com) [060325 09:58]:

> So we had chmod in Perl5, I would like to make sure it works in
> Perl6 as well with slight modifications.
>
> LIST = chmod MODE, LIST

My feeling is that this function design is a bit of a mistake. Usually,
one perl function maps on one operating-system function, but in this case
it doesn't: it simulated the common chmod(1) user command.

User commands have a different purpose and application than program
calls. If chmod complains to a used about "no permission", the used
can understand that, filter out the files and handle accordingly.
However, applications should have a thorough error-handling.


>
> 1) In list context it would return the names of the files successfully
> changed .
> In scalar context it should be the number of files successfully changed
> as it is in Perl5

Perl's chmod can better simulate chmod(2) than chmod(1), and see the latter
as something derived. If anything is returned, it should be an
error-object, not the file name.

So, the "real" core chmod is sub chmod($mode, $file)

Of course, besides that you may implement a version which accepts a list,
but that is certainly not needed except for perl5 compatibility...

> 2) In addition to the octet representation it would also be ready to receive
> the unix style mode representation which is string
> one or more of the letters ugoa,
> one of the symbols +-=
> one or more of the letters rwxXstugo

would be nice... but platform independent?

> 3) While some of the modes are UNIX specific, it would be nice to find similar
> modes in other operating system and do the right thing there too.
> e.g. "all" in UNIX would map to "Everyone" in Windows/NTFS

Then we come into the dangerous dungeons of File::Spec. It would be so
nice to redesign that:

my Dir $top .= new($root);
my Dir $etc = $top.cd('etc');
$etc.chmod('g+w');
my Stat $s = $etc.file('passwd').stat;
for $cwd.glob('*.c') -> .chmod('a+w');

my File $f .= unix('/etc/passwd');

When it is easy to manupulate dirs and files as objects, than we can hide
all these OS-specific calls about directories, paths, modes and stuff
in the objects, outside the core language.

> 4) "filename".chmod(MODE) should also work and I guess
> <file1 file2 file3>.chmod(MODE) should also work on those 3 files

Should all methods which accept a string as argument have an alternative method
in the string class? Why then in this case?
--
Regards,

MarkOv

------------------------------------------------------------------------
Mark Overmeer MSc MARKOV Solutions
Ma...@Overmeer.net solu...@overmeer.net
http://Mark.Overmeer.net http://solutions.overmeer.net

Gabor Szabo

unread,
Mar 26, 2006, 2:26:40 PM3/26/06
to perl6-l...@perl.org
On 3/26/06, Mark Overmeer <ma...@overmeer.net> wrote:
> > LIST = chmod MODE, LIST
>
> My feeling is that this function design is a bit of a mistake. Usually,
> one perl function maps on one operating-system function, but in this case
> it doesn't: it simulated the common chmod(1) user command.

[...]

> Of course, besides that you may implement a version which accepts a list,
> but that is certainly not needed except for perl5 compatibility...

If we look at Perl just as a high-level language than you might be right,
and I really liked the object being returned idea, but I think Perl should
also keep serving the system administrators with much simpler needs.

Perl was quite a good replacement to shell scripting but there are several
places where writing shell commands is sill much simpler. It would be nice
if the this end of the programming spectrum - writing one liners and
small scripts - would be also further strengthened.

Gabor

Mark Overmeer

unread,
Mar 26, 2006, 3:07:10 PM3/26/06
to Gabor Szabo, perl6-l...@perl.org
* Gabor Szabo (sza...@gmail.com) [060326 19:26]:

> On 3/26/06, Mark Overmeer <ma...@overmeer.net> wrote:
> > > LIST = chmod MODE, LIST
> >
> > My feeling is that this function design is a bit of a mistake. Usually,
> > one perl function maps on one operating-system function, but in this case
> > it doesn't: it simulated the common chmod(1) user command.
>
> If we look at Perl just as a high-level language than you might be right,
> and I really liked the object being returned idea, but I think Perl should
> also keep serving the system administrators with much simpler needs.

"Simple tasks must be simple, and complex ones must be possible"

Once upon a time, handling file(name)s was simple. But not anymore:
os-specifics and character-sets are a pain. One of Perl's targets is
to be platform independent: with only a few letters more you can
achieve that wrt file- and directory handling.
--
MarkOv

------------------------------------------------------------------------

Larry Wall

unread,
Mar 26, 2006, 5:40:03 PM3/26/06
to perl6-l...@perl.org

I suspect that can work simply by failing-over from SMD to MMD.

On the original question, I see it more as a junctional issue.
Assuming we have only chmod($,$), this sould autothread:

unless chmod MODE, all(@files) -> $oops {
???;
profit();
}

Larry

Larry Wall

unread,
Mar 26, 2006, 8:07:10 PM3/26/06
to perl6-l...@perl.org
On Sun, Mar 26, 2006 at 02:40:03PM -0800, Larry Wall wrote:
: On the original question, I see it more as a junctional issue.

: Assuming we have only chmod($,$), this sould autothread:
:
: unless chmod MODE, all(@files) -> $oops {
: ???;
: profit();
: }

Except that junctional logic is allowed to fail as soon as it can be
falsified, so if some set of file is not chmodable, you'd randomly
get an error message for one of them. You really need something that
drives it to completion, like hyperop, or a pipe, or a list operator.
(Which is sort of what we already have, but the return status of such a
list operator should probably be a list, or something that does list.)

On the other hand, if it's only the boolean context that wants
to short-circuit a junction, maybe binding to $oops drives the
autothreading to completion somehow. (Or asking for a list value
from $oops, more likely).

Larry

toby

unread,
Mar 26, 2006, 10:19:11 PM3/26/06
to
Mark Overmeer wrote:
> * Gabor Szabo (sza...@gmail.com) [060325 09:58]:
> > So we had chmod in Perl5, I would like to make sure it works in
> > Perl6 as well with slight modifications.
> >
> > LIST = chmod MODE, LIST
>
> My feeling is that this function design is a bit of a mistake. Usually,
> one perl function maps on one operating-system function, but in this case
> it doesn't: it simulated the common chmod(1) user command.

But incompletely.

>
> User commands have a different purpose and application than program
> calls. If chmod complains to a used about "no permission", the used
> can understand that, filter out the files and handle accordingly.
> However, applications should have a thorough error-handling.
> >
> > 1) In list context it would return the names of the files successfully
> > changed .
> > In scalar context it should be the number of files successfully changed
> > as it is in Perl5
>
> Perl's chmod can better simulate chmod(2) than chmod(1),

I think this is an excellent observation. The OP's proposal is nice
sugar, but still only goes part way: For instance, how would you
cleanly implement "-R" (a frequently used option)?

> and see the latter
> as something derived. If anything is returned, it should be an
> error-object, not the file name.
>
> So, the "real" core chmod is sub chmod($mode, $file)

> ...

Jonathan Lang

unread,
Mar 27, 2006, 1:56:22 AM3/27/06
to perl6-l...@perl.org
Mark Overmeer wrote:
> * Larry Wall (la...@wall.org) [060327 01:07]:

> > On Sun, Mar 26, 2006 at 02:40:03PM -0800, Larry Wall wrote:
> > : On the original question, I see it more as a junctional issue.
> > : Assuming we have only chmod($,$), this sould autothread:
> > :
> > : unless chmod MODE, all(@files) -> $oops {
> > : ???;
> > : profit();
> > : }
> >
> > Except that junctional logic is allowed to fail as soon as it can be
> > falsified,
>
> $oops being the filename or the error? To produce a good error
> report, you need both.
>
> To be compatible with Perl5, the order of the @files must be preserved.
>
> Is it really worth it to design a new syntax to avoid the use of 'for'
> with chmod? In more characters as well?

What about this:

unless all(chmod MODE, »@files«) -> $oops {
???;
profit();
}

Hyperoperate on the list in order to convert a "($$) returns $"
signature into a de facto "($@) returns @" signature, then feed the
resulting list into a junctive function to collapse it into a single
truth value.

--
Jonathan "Dataweaver" Lang

Mark Overmeer

unread,
Mar 27, 2006, 1:44:19 AM3/27/06
to perl6-l...@perl.org
* Larry Wall (la...@wall.org) [060327 01:07]:
> On Sun, Mar 26, 2006 at 02:40:03PM -0800, Larry Wall wrote:
> : On the original question, I see it more as a junctional issue.
> : Assuming we have only chmod($,$), this sould autothread:
> :
> : unless chmod MODE, all(@files) -> $oops {
> : ???;
> : profit();
> : }
>
> Except that junctional logic is allowed to fail as soon as it can be
> falsified,

$oops being the filename or the error? To produce a good error
report, you need both.

To be compatible with Perl5, the order of the @files must be preserved.

Is it really worth it to design a new syntax to avoid the use of 'for'
with chmod? In more characters as well?

--

Damian Conway

unread,
Mar 27, 2006, 6:30:18 AM3/27/06
to perl6-l...@perl.org
Jonathan Lang wrote:

> How important is it that perl 6 maintains the notion that $foo and
> @foo are entirely different things?

Very.


> Also, there's the matter of "unneccessary paperwork": if the only
> thing that I use the return value for is a boolean test, then all of
> the effort involved in loading the filenames into a list was wasted
> effort. Is there a way that the "lazy evaluation" concept could be
> extended to function return values? Something like:
>
>
>>Partial Perl 5 implementation:
>>
>> sub chmod {
>> my ($mode, @files) = @_;
>>
>> $mode = _normalize_mode($mode);
>>
>> my @failed;
>> FILE:
>> for my $file (@files) {
>> next FILE if chmod $mode, $file;
>> push @failed, $file;
>> }
>>
>> use Contextual::Return;
>
>
> # at this point, have the sub temporarily suspend operation.
>
>
>> return
>> BOOL { !@failed }
>> SCALAR { 0+@failed }
>> LIST { @failed }
>> }

You haven't studied the Contextual::Return module closely enough. Lazy
evaluation of the different return contexts is precisely what it already does. :-)

Damian

Damian Conway

unread,
Mar 27, 2006, 6:50:27 AM3/27/06
to Larry Wall, perl6-l...@perl.org
Larry wrote:

Hmmmm. I'm not sure I want to extend the QM metaphor to quite that much
magical action at a distance. ;-)

Especially since, if the boolean context doesn't itself drive the distributed
chmod() to completion, then something like:

die unless chmod $MODE, all(@files);

is potentially going to leave your filesystem in an unpredictable state. :-(

In other words, this is another example of "Don't use junctions in actions
with side-effects".


What we have here is a close analogy to the reporting requirements of pattern
matching. We have an operation that we want to have return several (possibly
lazily computed) pieces of outcome status. That's why we use an Match object
for the outcomes of pattern matches, and that's why I suggested a similarly
structured Outcome object for chmod (and other built-ins). It feels like
there's a more universal "status reporting from list-op" mechanism here, just
waiting to be generalized out.

Damian

Jonathan Lang

unread,
Mar 27, 2006, 9:07:42 AM3/27/06
to dam...@conway.org, Larry Wall, perl6-l...@perl.org
Damian Conway wrote:
> In other words, this is another example of "Don't use junctions in actions
> with side-effects".

Why not tag functions with side-effects as such (using a trait to that
effect), and then say that short-circuit operators don't short-circuit
when side-effects are involved? Or provide adverbs for the junctive
functions that can be used to change their short-circuiting behavior.
Or both.

--
Jonathan Lang

0 new messages