Was ist der Unterschied zwischen dem direkten Ausführen eines Befehls und mit `bash -c`?

8

Was ist für einen Befehl (eingebaut oder extern) der Unterschied, wenn Sie ihn direkt in einem Bash-Shell-Prozess und mit bash -cin der Bash-Shell ausführen? Was sind ihre Vor- und Nachteile im Vergleich zueinander?

For example, in a bash shell, run `date` directly, and run `bash -c
date`. Also consider a builtin command instead of an external one.
Tim
quelle

Antworten:

12
  1. Mit dieser -cOption können Programme Befehle ausführen. Es ist viel einfacher zu gabeln und zu tun

    execl("/bin/sh", "sh", "-c", "date | od -cb  &&  ps > ps.out", NULL);

    als es ist zu verzweigen, erstellen Sie eine Pipe, gabeln Sie erneut, rufen Sie execljedes untergeordnete Element auf, rufen Sie an wait, überprüfen Sie den Exit-Status, gabeln Sie erneut, rufen Sie auf close(1), öffnen Sie die Datei, stellen Sie sicher, dass sie in Dateideskriptor 1 geöffnet ist, und führen Sie eine andere aus execl. Ich glaube, dass dies der Grund war, warum die Option überhaupt geschaffen wurde.

    Die system()Bibliotheksfunktion führt einen Befehl mit der obigen Methode aus.

  2. Es bietet eine Möglichkeit, einen beliebig komplexen Befehl zu übernehmen und ihn wie einen einfachen Befehl aussehen zu lassen. Dies ist nützlich bei Programmen, die einen benutzerdefinierten Befehl ausführen, z. B. find … -execoder xargs. Aber das wusstest du schon; Es war Teil der Antwort auf Ihre Frage: Wie kann ein zusammengesetzter Befehl als Argument für einen anderen Befehl angegeben werden?
  3. Dies kann nützlich sein, wenn Sie eine andere interaktive Shell als Bash ausführen. Umgekehrt können Sie diese Syntax verwenden, wenn Sie bash ausführen

    $ ash -c " Befehl "
                 ︙
     
    $ csh -c " Befehl "
                 ︙
     
    $ dash -c " Befehl "
                 ︙
     
    $ zsh -c " Befehl "
                 ︙

    einen Befehl in einer anderen Shell ausführen, da alle diese Shells auch die -cOption erkennen. Natürlich könnten Sie mit das gleiche Ergebnis erzielen

    $ Asche
    ash $ Befehl
            ︙
    Asche $ Ausgang
     
    $ cshBefehl 
    csh $
            ︙
    csh $ exit
     
    $ dash
    Dash $ Befehl
            ︙
    dash $ exit
     
    $ zshBefehl 
    zsh $
            ︙
    zsh $ exit

    Ich habe ash$ usw. verwendet, um die Eingabeaufforderungen der verschiedenen Muscheln zu veranschaulichen. Sie würden diese wahrscheinlich nicht wirklich bekommen.

  4. Dies kann nützlich sein, wenn Sie einen Befehl in einer "frischen" Bash-Shell ausführen möchten. zum Beispiel,

    $ ls -lA
    total 0
    -rw-r--r-- 1 gman gman   0 Apr 14 20:16 .file1
    -rw-r--r-- 1 gman gman   0 Apr 14 20:16 file2
    
    $ echo *
    file2
    
    $ shopt -s dotglob
    
    $ echo *
    .file1 file2
    
    $ bash -c "echo *"
    file2

    oder

    $ type shift
    shift is a shell builtin
    
    $ alias shift=date
    
    $ type shift
    shift is aliased to ‘date’
    
    $ bash -c "type shift"
    shift is a shell builtin
  5. Das Obige ist eine irreführende Übervereinfachung. Wenn bash mit ausgeführt wird -c, wird es als nicht interaktive Shell betrachtet und nicht gelesen ~/.bashrc, sofern nicht anders -iangegeben. Damit,

    $ Typ cp
    cp ist auf 'cp -i'           # aliasiert. Definiert in ~ / .bashrc
     
    $ cp .file1 file2
    cp: 'file2' überschreiben? n
     
    $ bash -c "cp .file1 file2"
                                      # Bestehende Datei wird ohne Bestätigung überschrieben!
    $ bash -c -i "cp .file1 file2"
    cp: 'file2' überschreiben? n

    Sie könnten verwenden -ci, -i -coder -icstatt -c -i.

    Dies gilt wahrscheinlich in gewissem Maße für die anderen in Absatz 3 genannten Shells, sodass die Langform (dh die zweite Form, bei der es sich tatsächlich um genau die gleiche Menge an Eingabe handelt) möglicherweise sicherer ist, insbesondere wenn Sie Initialisierungs- / Konfigurationsdateien eingerichtet haben für diese Muscheln.

  6. Wie Wildcard erklärt hat, können Änderungen an der in der Subshell vorgenommenen Umgebung keine Auswirkungen auf die übergeordnete Shell (aktuelles Verzeichnis, Umgebungswerte) haben , da Sie einen neuen Prozessbaum (einen neuen Shell-Prozess und möglicherweise dessen untergeordnete Prozesse) ausführen Variablen, Funktionsdefinitionen usw.) Daher ist es schwer vorstellbar, dass ein Shell-Befehl eingebaut ist, der nützlich wäre, wenn er von ausgeführt wird sh -c.  ,, und kann Hintergrundjobs, die von der übergeordneten Shell gestartet fgwurden bg, jobsnicht beeinflussen oder darauf zugreifen oder auf waitsie warten.  Dies entspricht im Wesentlichen dem normalen Ausführen direkt von der interaktiven Shell aus.  ist eine große Zeitverschwendung.  undsh -c "exec some_program"some_programsh -c exitulimitumask könnte die Systemeinstellungen für den untergeordneten Prozess ändern und dann beenden, ohne sie auszuüben.

    Fast der einzige eingebaute Befehl, der in einem sh -cKontext funktionsfähig wäre, ist kill. Natürlich, dass die Befehle nur erzeugen Ausgang ( echo, printf, pwdund type) nicht betroffen ist, und, wenn Sie eine Datei schreiben, wird das bestehen bleiben.

  7. Natürlich können Sie ein eingebautes in Verbindung mit einem externen Befehl verwenden. z.B,
    sh -c "cd some_directory ; some_program "
    Mit einer normalen Unterschale können Sie jedoch im Wesentlichen den gleichen Effekt erzielen:
    (cd some_directory ; some_program )
    das ist effizienter. Das gleiche (beide Teile) kann für so etwas gesagt werden
    sh -c "umask 77; some_program "
    oder ulimit(oder shopt). Und da Sie -cnach der Komplexität eines vollständigen Shell-Skripts einen beliebig komplexen Befehl eingeben können, haben Sie möglicherweise Gelegenheit, das Repertoire der integrierten Funktionen zu verwenden. zB source, read, export, times, setund unset, usw.
G-Man sagt "Reinstate Monica"
quelle
+1, außer ich denke du gehst mit Builtins zu weit. Um klar zu sein, echo printf type pwdsind eingebaute; so sind set shopt shift read readarray mapfile trap declare/typeset export local let readonly unsetdie in einem mäßig kompliziert nützlich sein , noch nicht die Eltern beeinflussen , sondern kann -c.
dave_thompson_085
Worum geht es dir? Haben Sie meine sechste Kugel gelesen, in der ich sagte, dass eingebaute Funktionen in Verbindung mit externen Befehlen nützlich sind? Wollen Sie damit sagen, dass ich in Punkt 6 weitere Beispiele nennen sollte?
G-Man sagt "Reinstate Monica"
Vielen Dank. Jemand sagte, dass Ihre Antwort auch eine andere Frage beantwortet hat , aber ist das wahr?
Tim
@ Tim: Welche Frage? Ich sehe fünf Fragezeichen in dieser „Frage“. OK, ich mache Witze - ein bisschen . Worüber bist du dir noch nicht sicher? Ich habe ein Beispiel für sh -cdie Verwendung mit einer komplexen Befehlszeile gezeigt, die drei Programme enthält, eine Pipe, eine &&und eine Umleitung. Ich habe ein Beispiel dafür gezeigt, wie es mit einer zusammengesetzten Befehlszeile verwendet wird cd, die a ;, a und ein Programm enthält. Ich habe ein Beispiel dafür gezeigt, wie es verwendet wird exec. und ich sagte , es verwendet werden könnte , mit eingebauten Funktionen wie echo, kill, printf, pwdund type(und auch exit, ulimitund umask). Was willst du noch wissen? … (Fortsetzung)
G-Man sagt 'Reinstate Monica'
(Fortsetzung)… Wenn Sie meinen: „Bedeutet das, execve()dass ein Skript bearbeitet werden kann?“, (1) das hat nichts damit zu tun bash -c, und (2) welche Nachforschungen haben Sie angestellt? Die execveManpage beantwortet dies und eine Suche auf dieser Site ergibt dies , das , das , das , das und das .
G-Man sagt "Reinstate Monica"
5

Laufen bash -c "my command here"vs. nur Laufen unterscheidet my command heresich hauptsächlich darin, dass erstere eine Subshell startet und letztere die Befehle in der aktuellen Shell ausführt.

Was integrierte Befehle im Vergleich zu externen Befehlen betrifft, hat dies keine wirkliche Beziehung - alles , was Sie in der aktuellen Shell ausführen können , können Sie in einer Subshell ausführen.

Es gibt jedoch eine Reihe von Unterschieden bei den Auswirkungen:

  • In der Subshell vorgenommene Änderungen an der Umgebung können sich nicht auf die übergeordnete Shell auswirken (aktuelles Verzeichnis, Werte von Umgebungsvariablen, Funktionsdefinitionen usw.).
  • In der übergeordneten Shell festgelegte Variablen, die nicht exportiert wurden, sind in der Subshell nicht verfügbar.

Dies ist alles andere als eine erschöpfende Liste von Unterschieden, enthält jedoch den entscheidenden Punkt: Sie führen einen anderen Prozess mit aus bash -c; Es ist nicht der gleiche Vorgang wie bei Ihrer ursprünglichen Shell.

Es gibt auch einen Leistungseinbruch, der durch das Laichen einer Unterschale entsteht. Dies ist am relevantesten, wenn Ihr Skript häufig ausgeführt wird oder wenn sich Ihr Befehl in einer Schleife befindet.

Platzhalter
quelle
1
Zu Ihrer Information, ich habe Ihre Antwort in meiner Antwort zitiert. Ich habe versucht, Sie von dort aus anzupingen, weil ich wusste, dass das nicht funktioniert.
G-Man sagt "Reinstate Monica"
2

Die Option -c führt grundsätzlich ein Mini-Shell-Skript aus, das als CLI-Argument und nicht als Datei bereitgestellt wird.

$ bash -c the_script the_scriptname 1 2 3 

ist praktisch gleichbedeutend mit:

$ echo the_script > the_scriptname
$ bash the_scriptname 1 2 3
$ rm the_scriptname

Wie siehst du aus:

$ bash -c 'printf " ->%s\n" $0 "$@"; echo $-;' scriptname 1 2 3
   ->scriptname
   ->1
   ->2
   ->3
  hBc

(Auf Englisch: $ 0 == scriptname; $ @ == (1 2 3); und bash wird: h ash-Befehle; B- Race-Erweiterung durchführen, und es wurde mit dem -cFlag ausgeführt)

und:

 $ echo 'printf " ->%s\n" $0 "$@"; echo $-;' > scriptname
 $ bash scriptname 1 2 3 
 ->scriptname
 ->1
 ->2
 ->3
 hB
PSkocik
quelle
-1

-c Zeichenfolge

Wenn die Option -c vorhanden ist, werden Befehle aus der Zeichenfolge gelesen. Wenn nach der Zeichenfolge Argumente vorhanden sind, werden diese den Positionsparametern zugewiesen, beginnend mit $ 0.

Dies wird Ihre Fragen lösen, denke ich

rɑːdʒɑ
quelle
Vielen Dank. Kannst du meine Fragen explizit erklären?
Tim