system#
Εκτελεί ένα ξεχωριστό πρόγραμμα και περιμένει να τελειώσει.
Η system κάνει ακριβώς το ίδιο πράγμα με την exec, με τη διαφορά ότι πρώτα γίνεται fork και η γονική διεργασία περιμένει το παιδί να τερματίσει. Η τιμή επιστροφής είναι η κατάσταση αναμονής του παιδιού, όχι η έξοδός του - αν θέλετε την έξοδο μιας εντολής, χρησιμοποιήστε αντί αυτής backticks ή qx//.
Σύνοψη#
system LIST
system PROGRAM LIST
Η έμμεση μορφή PROGRAM LIST ψεύδεται στο πρόγραμμα για το ίδιο του το όνομα: το PROGRAM είναι το αρχείο που εκτελείται πραγματικά, ενώ το πρώτο στοιχείο της LIST γίνεται argv[0] μέσα στο παιδί. Ίδιο κόλπο με την exec.
Τι επιστρέφεται#
Η τιμή επιστροφής είναι η ωμή λέξη κατάστασης από την υποκείμενη κλήση wait - η ίδια τιμή που προσγειώνεται στην $? μετά την κλήση. Για να ανακτήσετε τον πραγματικό κωδικό εξόδου του προγράμματος, μετατοπίστε δεξιά κατά οκτώ:
system("make", "install");
my $exit = $? >> 8;
Το -1 σημαίνει ότι το πρόγραμμα δεν μπόρεσε καθόλου να ξεκινήσει (ή ότι η ίδια η wait απέτυχε)· επιθεωρήστε την $! για τον λόγο. Επιστροφή 0 σημαίνει ότι το παιδί εξήλθε με επιτυχία με κατάσταση 0.
Εκτέλεση μέσω κελύφους έναντι απευθείας#
Η επεξεργασία ορισμάτων εξαρτάται από τη μορφή της LIST, και αντικατοπτρίζει ακριβώς την exec:
Περισσότερα από ένα ορίσματα (ή πίνακας με περισσότερα από ένα στοιχεία): το πρώτο στοιχείο είναι το πρόγραμμα, τα υπόλοιπα τα ορίσματά του. Το κέλυφος δεν καλείται· η
execvpτρέχει το πρόγραμμα απευθείας. Αυτή είναι η ασφαλής μορφή.Ακριβώς ένα βαθμωτό όρισμα: η Perl το σαρώνει για μετα-χαρακτήρες κελύφους. Αν υπάρχουν, ολόκληρη η συμβολοσειρά περνά στο
/bin/sh -cγια ανάλυση. Αν δεν υπάρχουν, η Perl τη διασπά σε λευκούς χαρακτήρες και καλεί απευθείας τηνexecvp- εξοικονομώντας ένα κέλυφος.
Προτιμήστε τη μορφή λίστας όποτε τα ορίσματα προέρχονται από μη έμπιστη είσοδο ή περιέχουν χαρακτήρες που το κέλυφος θα ερμήνευε:
system("ls", "-l", $dir); # safe, no shell
system("ls -l $dir"); # shell parses $dir - hazardous
Σήματα έναντι exit#
Η λέξη κατάστασης συνδυάζει τρία κομμάτια πληροφορίας: έναν αριθμό σήματος (αν το παιδί τερμάτισε από σήμα), μια σημαία core-dump και την τιμή εξόδου. Αποκωδικοποιήστε την ρητά όταν χρειάζεται να τα ξεχωρίσετε:
system(@cmd);
if ($? == -1) {
print "failed to execute: $!\n";
}
elsif ($? & 127) {
printf "child died with signal %d, %s coredump\n",
($? & 127), ($? & 128) ? 'with' : 'without';
}
else {
printf "child exited with value %d\n", $? >> 8;
}
Για δομημένη αποκωδικοποίηση, επιθεωρήστε την ${^CHILD_ERROR_NATIVE} - την πλήρη OS-native λέξη κατάστασης - με τις μακροεντολές WIFEXITED, WEXITSTATUS, WIFSIGNALED, WTERMSIG από το POSIX:
use POSIX qw(WIFEXITED WEXITSTATUS WIFSIGNALED WTERMSIG);
system(@cmd);
my $n = ${^CHILD_ERROR_NATIVE};
if (WIFEXITED($n)) { my $code = WEXITSTATUS($n); ... }
if (WIFSIGNALED($n)) { my $sig = WTERMSIG($n); ... }
Τα SIGINT και SIGQUIT αγνοούνται στον γονέα όσο τρέχει το παιδί. Αν θέλετε το δικό σας πρόγραμμα να τερματίσει όταν ο χρήστης πατήσει Ctrl-C κατά τη διάρκεια της system, ελέγξτε οι ίδιοι την κατάσταση επιστροφής και επανεκπέμψτε:
system(@cmd);
kill 'INT', $$ if ($? & 127) == 2; # re-raise SIGINT on self
Εκκένωση stdio#
Πριν το fork, η Perl επιχειρεί να εκκενώσει κάθε filehandle ανοιχτό για έξοδο. Αυτό αποτρέπει τη διπλή εμφάνιση ενταμιευμένων γραμμών από γονέα και παιδί. Η εκκένωση είναι best-effort· σε πλατφόρμες όπου είναι αναξιόπιστη, ορίστε την $| ($AUTOFLUSH) ή καλέστε τη μέθοδο autoflush από το IO::Handle στα handles που σας ενδιαφέρουν.
Το ιδίωμα die#
Ο κανονικός έλεγχος - λιτός, και ενσωματώνει τη λέξη κατάστασης στο μήνυμα ώστε ο καλών να μπορεί ακόμη να την αποκωδικοποιήσει:
my @args = ("command", "arg1", "arg2");
system(@args) == 0
or die "system @args failed: $?";
Για ένα άρθρωμα που θα έπρεπε να εκτοξεύει σε κάθε αποτυχημένη system (και πολλά άλλα κομμάτια της Perl), χρησιμοποιήστε την pragma autodie.
Παραδείγματα#
Εκτέλεση εντολής χωρίς να ληφθεί υπόψη το αποτέλεσμα:
system("clear");
Εκτέλεση εντολής, τερματισμός σε αποτυχία, και διατήρηση της κατάστασης ανέπαφης για κατάντη επιθεώρηση:
system("tar", "xf", $archive) == 0
or die "untar $archive failed: $?";
Ανίχνευση του αν είναι διαθέσιμο ένα πρόγραμμα τρέχοντάς το με --version και απορρίπτοντας την έξοδό του:
my $ok = system("which $prog >/dev/null 2>&1") == 0;
Εκτέλεση κάτω από συγκεκριμένο κέλυφος ρητά, παρακάμπτοντας την ευρετική ανίχνευσης μετα-χαρακτήρων της Perl:
system("/bin/bash", "-c", $pipeline);
Ψέμα για το argv[0] με χρήση της έμμεσης μορφής - ο πυρήνας εκτελεί το /usr/bin/vim, αλλά το πρόγραμμα βλέπει το όνομά του ως editor:
system { "/usr/bin/vim" } "editor", $file;
Οριακές περιπτώσεις#
Επιστροφή -1: το παιδί δεν δημιουργήθηκε ποτέ, ή απέτυχε η ίδια η
wait. Διακριτό από το «το παιδί εξήλθε με κατάσταση 255». Ελέγξτε την$!για τον λόγο - τυπικάENOENT(το πρόγραμμα δεν βρέθηκε) ήEACCES(μη εκτελέσιμο).Τιμή εξόδου 255 από κέλυφος: όταν χρησιμοποιείται η μορφή κελύφους και το
/bin/shδεν μπορεί να βρει το πρόγραμμα, το ίδιο το κέλυφος εξέρχεται με127. Προγράμματα που επιστρέφουν255από Perl τυπικά προέρχονται μέσωdieσε άλλο πρόγραμμα Perl.Αλληλεπίδραση χειριστή
SIGCHLD: ηsystemεσωτερικά κάνει fork και περιμένει. Ένας χειριστής$SIG{CHLD}μπορεί να παρατηρήσει ή να μπει σε race με αυτή την αναμονή· δείτε τοperlipcγια την πειθαρχία συγκομιδής.Ιδιοτροπίες κελύφους: όταν ενεργοποιείται η μορφή κελύφους, οι κωδικοί επιστροφής και η αναφορά σφαλμάτων είναι ό,τι λέει το
/bin/sh- όχι πάντα ό,τι επέστρεψε το υποκείμενο πρόγραμμα. Χρησιμοποιήστε τη μορφή λίστας για να το αποφύγετε.Δεν είναι για αποτύπωση εξόδου: η
systemγράφει την έξοδο του παιδιού στα κληρονομημέναSTDOUT/STDERR. Χρησιμοποιήστεqx//ή ανοίξτε σωλήνα μεopenαν χρειάζεστε την έξοδο ως συμβολοσειρά.Windows: μόνο η σύνταξη
system PROGRAM LISTαποφεύγει αξιόπιστα το κέλυφος. Η pperl τρέχει μόνο σε Linux, οπότε αυτό δεν ισχύει εδώ· σημειώνεται για φορητότητα.
Διαφορές από το upstream#
Πλήρως συμβατό με το upstream Perl 5.42.
Δείτε επίσης#
exec- αντικαθιστά την τρέχουσα διεργασία αντί να κάνει fork και αναμονή· ίδιοι κανόνες επεξεργασίας ορισμάτων με τηνsystemfork- δημιουργεί διεργασία-παιδί χωρίς να τρέξει νέο πρόγραμμα· ηsystemείναιfork+exec+waitpidwaitpid- συλλέγει συγκεκριμένο παιδί, χρησιμοποιείται όταν διαχειρίζεστε πολλαπλά παιδιά απευθείαςqx- εκτελεί εντολή και αποτυπώνει την έξοδό της ως συμβολοσειρά· αυτό που θέλετε όταν η στόχευση stdio τηςsystemδεν αρκεί$?- λέξη κατάστασης σφάλματος παιδιού που ορίζεται απόsystem, backticks,closeσε σωλήνα καιwait$!- errno μετά από αποτυχημένο fork ή exec (τιμή επιστροφής-1)${^CHILD_ERROR_NATIVE}- πλήρης OS-native κατάσταση αναμονής για αποκωδικοποίηση με τις μακροεντολέςW*τουPOSIX