Διεργασίες

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 και αναμονή· ίδιοι κανόνες επεξεργασίας ορισμάτων με την system

  • fork - δημιουργεί διεργασία-παιδί χωρίς να τρέξει νέο πρόγραμμα· η system είναι fork + exec + waitpid

  • waitpid - συλλέγει συγκεκριμένο παιδί, χρησιμοποιείται όταν διαχειρίζεστε πολλαπλά παιδιά απευθείας

  • qx - εκτελεί εντολή και αποτυπώνει την έξοδό της ως συμβολοσειρά· αυτό που θέλετε όταν η στόχευση stdio της system δεν αρκεί

  • $? - λέξη κατάστασης σφάλματος παιδιού που ορίζεται από system, backticks, close σε σωλήνα και wait

  • $! - errno μετά από αποτυχημένο fork ή exec (τιμή επιστροφής -1)

  • ${^CHILD_ERROR_NATIVE} - πλήρης OS-native κατάσταση αναμονής για αποκωδικοποίηση με τις μακροεντολές W* του POSIX