Wann ist der richtige Zeitpunkt (und die falsche Zeit) Backticks zu benutzen?

StackOverflow https://stackoverflow.com/questions/115809

  •  02-07-2019
  •  | 
  •  

Frage

Viele beginnen Programmierer schreiben Code wie folgt:

sub copy_file ($$) {
  my $from = shift;
  my $to = shift;

  `cp $from $to`;
}

Ist das schlimm, und warum? Sollte jemals Backticks verwendet werden? Wenn ja, wie?

War es hilfreich?

Lösung

Ein paar Leute haben bereits erwähnt, dass Sie sollten nur Backticks verwenden:

  • Sie müssen erfassen (oder supress) die Ausgabe.
  • Es gibt keine integrierte Funktion oder Perl-Modul die gleiche Aufgabe zu tun, oder Sie haben einen guten Grund, nicht das Modul oder Einbau-verwenden.
  • Sie sanieren Ihre Eingabe.
  • Sie überprüfen den Rückgabewert.

Leider Dinge wie der Rückgabewert Überprüfung richtig kann eine ziemliche Herausforderung sein. Hat es auf ein Signal sterben? Habe es bis zur Fertigstellung, läuft aber einen lustigen Exit-Status zurückkehren? Die Standard-Möglichkeiten zu versuchen, $? zu interpretieren sind einfach schrecklich.

Ich würde empfehlen, die IPC :: System mit :: Simple Moduls capture() und system() Funktionen statt Backticks. Die capture() Funktion funktioniert genauso wie Backticks, mit der Ausnahme, dass:

  • Sie liefert eine detaillierte Diagnose, wenn der Befehl nicht startet, durch ein Signal getötet wird, oder gibt einen unerwarteten Ausgang Wert.
  • Sie liefert eine detaillierte Diagnose, wenn übergeben verdorbenen Daten.
  • Sie bietet einen einfachen Mechanismus für die Angabe akzeptablen Ausgang Werte.
  • Es ermöglicht Ihnen, Backticks ohne die Schale zu nennen, wenn Sie wollen.
  • Sie bietet zuverlässige Mechanismen für die Schale zu vermeiden, auch wenn Sie nur ein Argument verwenden.

Die Befehle auch konsequent für alle Betriebssysteme und Perl-Versionen arbeiten, im Gegensatz zu Perl eingebauten in system() die für verdorbene Daten kann nicht überprüfen, wenn sie mit mehreren Argumenten auf ältere Versionen von Perl (zB 5.6.0 mit mehreren Argumenten) genannt, oder die die Schale ohnehin unter Windows aufrufen können.

Als Beispiel der folgende Code-Schnipsel werden die Ergebnisse eines Aufrufs perldoc in einem skalaren speichern, vermeidet die Schale, und löst eine Ausnahme, wenn die Seite nicht gefunden werden kann (da Perldoc liefert 1).

#!/usr/bin/perl -w
use strict;
use IPC::System::Simple qw(capture);

# Make sure we're called with command-line arguments.
@ARGV or die "Usage: $0 arguments\n";

my $documentation = capture('perldoc', @ARGV);

IPC :: System :: Simple ist reines Perl, Werke auf 5.6.0 und höher, und hat keine Abhängigkeiten, die mit dem Perl-Distribution normalerweise nicht kommen würden. (Unter Windows hängt es von einem Win32 :: Modul, das sowohl mit Activestate und Strawberry Perl kommt).

Disclaimer: Ich bin der Autor IPC :: System :: Simple , so kann ich eine gewisse Tendenz zeigen.

Andere Tipps

Die Regel ist einfach: nie Backticks verwenden, wenn Sie einen eingebauten, zu tun die gleiche Arbeit finden können oder wenn ihr ist ein robustes Modul auf dem CPAN, die es für Sie tun. Backticks verlassen sich oft auf unportable Code und selbst wenn Sie die Variablen untaint, können Sie sich immer noch zu viele Sicherheitslücken öffnen.

Nie Verwendung mit Backticks Datennutzer, es sei denn Sie haben sehr eng spezifiziert, was erlaubt ist (nicht das, was nicht erlaubt ist - verpassen Sie Dinge)! Das ist sehr, sehr gefährlich.

Backticks sollen verwendet werden, wenn und nur wenn Sie die Ausgabe eines Befehls erfassen müssen. Andernfalls System () verwendet werden. Und natürlich, wenn es eine Perl-Funktion oder CPAN-Modul, das die Arbeit erledigt, soll dies statt entweder verwendet werden.

In jedem Fall werden zwei Dinge dringend empfohlen:

Zuerst sanieren alle Eingänge: Verwenden Taint-Modus (T), wenn der Code auf mögliche nicht vertrauenswürdigen Eingaben ausgesetzt ist. Auch wenn es nicht, stellen Sie sicher (oder verhindern) flippige Zeichen wie Raum zu handhaben oder die drei Arten des Zitats.

Zweitens Überprüfen des Return-Code , um sicherzustellen, dass der Befehl erfolgreich war. Hier ist ein Beispiel dafür, wie dies zu tun:

my $cmd = "./do_something.sh foo bar";
my $output = `$cmd`;

if ($?) {
   die "Error running [$cmd]";
}

Eine weitere Möglichkeit, stdout zu erfassen (zusätzlich zu pid und Exit-Code) verwenden IPC :: Open3 possibily negiert die Verwendung sowohl von System und Backticks.

Verwenden Sie Backticks, wenn Sie die Ausgabe des Befehls zu sammeln.

Ansonsten system() ist eine bessere Wahl, vor allem, wenn Sie nicht brauchen eine Shell aufzurufen Metazeichen oder Befehl Parsing zu behandeln. Sie können verhindern, dass eine Liste System, indem man (), zB system('cp', 'foo', 'bar') (allerdings würden Sie wahrscheinlich besser, ein Modul zu verwenden, für die insbesondere Beispiel:))

In Perl gibt es immer mehr als eine Art und Weise alles, was Sie tun wollen. Der primäre Punkt Backticks ist die Standardausgabe des Shell-Befehl in ein Perl-Variable zu erhalten. (In Ihrem Beispiel alles, was die cp Befehl druckt wird an den Aufrufer zurückgegeben werden.) Der Nachteil von Backticks in Ihrem Beispiel verwendet, wird Sie nicht überprüfen den Rückgabewert der Shell-Befehl; cp könnte scheitern und Sie würden nicht bemerken. Sie können dies mit dem speziellen Perl-Variable $ verwenden ?. Wenn ich einen Shell-Befehl ausführen möchten, neige ich dazu verwenden, System :

system("cp $from $to") == 0
    or die "Unable to copy $from to $to!";

(Beachten Sie auch, dass diese auf Dateinamen mit eingebetteten Leerzeichen fehlschlagen, aber ich nehme an, das ist nicht der Punkt in Frage.)

Hier ist ein konstruiertes Beispiel, wo Backticks könnten nützlich sein:

my $user = `whoami`;
chomp $user;
print "Hello, $user!\n";

Bei komplizierteren Fällen können Sie auch open als Rohr:

open WHO, "who|"
    or die "who failed";
while(<WHO>) {
    # Do something with each line
}
close WHO;

Von der "perlop" Man-Page:

  

Das bedeutet nicht, dass Sie aus gehen sollten   Ihr Weg Backticks zu vermeiden, wenn   sie sind der richtige Weg, um etwas zu bekommen   getan. Perl gemacht wurde ein Klebstoff zu sein   Sprache und eines der Dinge, die es   Leime zusammen ist, Befehle. Gerade   verstehen, was Sie bekommen   selbst in.

Für den Fall, dass Sie zeigen, werden unter Verwendung der File :: Copy Modul ist wahrscheinlich am besten. Aber um Ihre Frage zu beantworten, wenn ich mich in der Regel verlassen sich auf IPC einen Systembefehl ausführen müssen: : Run3 . Es bietet eine Vielzahl von Funktionen wie den Return-Code und den Standard und Fehlerausgang zu sammeln.

Was auch immer Sie tun, sowie Eingabebereinigung und den Rückgabewert des Codes überprüft, stellen Sie sicher, dass Sie rufen alle externen Programme mit ihren expliziten vollständigen Pfad. z.B. sagen

my $user = `/bin/whoami`;

oder

my $result = `/bin/cp $from $to`;

Zu sagen, nur „whoami“ oder „cp“, läuft Gefahr, versehentlich einen anderen Befehl als ausgeführt wird, was Sie bestimmt, wenn der Pfad der Benutzer ändert -., Die eine Sicherheitslücke, die es einem böswilligen Angreifer könnte versuchen, nutzen

Ihr Beispiel ist schlecht, weil es Perl builtins, was zu tun ist tragbar und in der Regel effizienter als die Graviszeichen Alternative.

Sie sollten nur verwendet werden, wenn es keine Perl builtin (oder Modul) Alternative. Dies ist sowohl für Backticks und system () aufruft. Backticks sollen für die Ausgabe des ausgeführten Befehls zu erfassen.

Backticks sollen nur verwendet werden, wenn Sie die Ausgabe aufnehmen möchten. Mit ihnen hier „sieht albern.“ Es ist zu clue jemand geht auf den Code in der Tatsache suchen, dass Sie mit Perl nicht sehr vertraut sind.

Verwenden Sie Backticks, wenn Sie Ausgabe zu erfassen. Verwenden Sie System, wenn Sie einen Befehl ausführen möchten. Ein Vorteil, den Sie gewinnen müssen, ist die Fähigkeit, den Rückgabestatus zu überprüfen. Verwenden Sie Module, soweit möglich für die Portabilität. In diesem Fall File :: Copy paßt die Rechnung.

In der Regel ist es am besten zu verwenden System anstelle von Backticks, weil:

  1. System ermutigt den Anrufer den Rückkehrcode des Befehls zu überprüfen.

  2. System erlaubt "indirektes Objekt" Notation, die sicherer ist und erhöht die Flexibilität.

  3. Backticks sind kulturell gebunden Scripting, Shell, die unter den Lesern des Codes nicht üblich sein könnte.

  4. Backticks verwenden minimale Syntax für das, was ein schwerer Befehl sein kann.

Ein Grund Benutzer temped werden könnte Backticks anstelle von System verwenden ist STDOUT von dem Benutzer zu verbergen. Das ist einfach und flexibel erreicht, indem der STDOUT- Strom umleiten:

my $cmd = 'command > /dev/null';
system($cmd) == 0 or die "system $cmd failed: $?"

Ferner von STDERR loszuwerden ist leicht zu bewerkstelligen:

my $cmd = 'command 2> error_file.txt > /dev/null';

In Situationen, in denen es Sinn macht, Backticks zu verwenden, zieht ich das QX verwenden {} , um zu betonen, dass es ein schwerer Befehl auftritt.

Auf der anderen Seite, einen anderen Weg, die damit zu tun kann wirklich helfen. Manchmal braucht man nur um zu sehen, was ein Befehl druckt nach STDOUT. Backticks, wenn wie in Shell-Skripten sind genau das richtige Werkzeug für den Job verwendet wird.

Perl hat eine gespaltene Persönlichkeit. Auf der einen Seite ist es eine große Skriptsprache, die die Verwendung einer Schale ersetzen kann. In dieser Art von einmaligen I-Watching-the-Ergebnis der Verwendung sind Backticks bequem.

Wenn eine Programmiersprache verwendet werden, sind Backticks vermieden werden. Dies ist ein Mangel an Fehlern Überprüfung und, wenn die separaten Programm ausführen Backticks vermieden werden kann, Effizienz gewonnen.

Abgesehen von den oben, sollte die Systemfunktion verwendet werden, wenn die Ausgabe des Befehls nicht verwendet wird.

Backticks sind für Amateure. Die kugelsichere Lösung ist ein „Safe Rohr Open“ (siehe „Mann perlipc“). exec Sie Ihren Befehl in einem anderen Prozess, mit dem Sie zum ersten futz mit STDERR erlaubt, setuid- etc. Vorteile: es tut nicht stützt sich auf der Shell @ARGV zu analysieren, im Gegensatz zu öffnen ( "$ cmd $ args | "), das ist unzuverlässig. Sie können STDERR umgeleitet und Benutzer priviliges ändern, ohne das Verhalten des Hauptprogramms zu ändern. Dies ist ausführlicher als Backticks, aber Sie können es in Ihrer eigenen Funktion wie run_cmd wickeln ($ cmd, @ args);


sub run_cmd {
  my $cmd = shift @_;
  my @args = @_;

  my $fh; # file handle
  my $pid = open($fh, '-|');
  defined($pid) or die "Could not fork";
  if ($pid == 0) {
    open STDERR, '>/dev/null';
    # setuid() if necessary
    exec ($cmd, @args) or exit 1;
  }
  wait; # may want to time out here?
  if ($? >> 8) { die "Error running $cmd: [$?]"; }
  while (<$fh>) {
    # Have fun with the output of $cmd
  }
  close $fh;
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top