I want to execute a couple of unix commands within perl. What's the best way to do so? Is it better to use qx or system()? Is there a good way to check if it fails? Can someone show me a good example? Thanks.
my $crflag=qx('/bin/touch /tmp/flag.done');
my $chgperm=qx('chmod 755 /tmp/flag.done');
vs.
开发者_如何学Pythonmy $crflag = '/bin/touch /tmp/flag.done';
my $chgperm ='chmod 755 /tmp/flag.done';
system ($crflag);
system ($chgperm);
There are a couple of problems with your code:
- You don't seem to want the output, meaning you'd want
system
, but these are very simple steps and should probably be done directly in Perl, instead of calling out to the shell.touch
is literally 1 call in Perl (2 if you count closing the file.) - There is a race condition, since you're creating the file, and then setting its permissions in two steps. Since this looks like a flag file, a race condition seems relevant, and thus you probably want an atomic create/setperms in one command.
- Since it's a flag file, you probably want mode
0644
instead of0755
.
In Perl, you can solve all of the above with something like this:
#!/usr/bin/perl
use Fcntl qw( :DEFAULT ); # Core module, for O_CREAT, etc. constants
use strict;
use warnings;
# You probably want 0644, as a flag file probably shouldn't be executable..?
sysopen( my $fh, '/tmp/flag.done', O_CREAT|O_EXCL|O_RDWR, 0644 )
# Sysopen returns a undef if unsuccessful, with an error message stored in $!
or die "$!";
# write to it here, if you need to.
close( $fh );
You can place this into a sub with whatever arguments you want to create a (much more) atomic creation step to avoid other processes interfering between the large number of calls to shell out twice to create the file and then reset its permissions. (There's still concerns with synchronization, so it could still be pre-empted, but this is overall a far better solution.)
There are other flags you may wish to use. Check perldoc perlopentut
and search for sysopen
for a small list, or check perldoc Fcntl
and your platform's documentation for a more comprehensive list. You may also wish to change the 0644
permissions to something more and less restrictive, and you may further wish to use locking; see perldoc -f flock
for information and code samples on advisory locking.
Besides the fact that both operations can be done trivially using builtins utime
and chmod
, IPC::System::Simple provides error checking.
use IPC::System::Simple qw( system );
system('/bin/touch /tmp/flag.done');
system('chmod 755 /tmp/flag.done');
Use system
along with $?
. Try to avoid using qx
when the output is not required.
system '/bin/touch /tmp/flag.done';
my $touch_status = $? >> 8;
system 'chmod 755 /tmp/flag.done';
my $chmod_status = $? >> 8;
精彩评论