Es gibt Variablen in der Shell wie $0
, $1
, $2
, $?
etc.
Ich habe versucht, die Shell- und Umgebungsvariablen mit dem folgenden Befehl zu drucken:
set
Diese Variablen waren jedoch nicht in der Liste enthalten.
Im Grunde genommen werden diese Variablen also nicht als Shell- / Umgebungsvariablen betrachtet, oder? (Auch wenn Sie sie ausgeben möchten, müssen Sie ihnen $
wie bei Shell- / Umgebungsvariablen ein voranstellen. )
export 3
drehen$3
in eine Umgebungsvariable. Sie können nichtunset 3
; und Sie können mit keinen$3
neuen Wert zuweisen3=val
.Antworten:
Variablen sind eine von drei verschiedenen Arten von Parametern in der Shell.
_
oder einem Buchstaben, gefolgt von null oder mehr Buchstaben, Zahlen oder_
.$1
,$2
...$0
verschiedenen Interpunktionszeichen.set
Zeigt nur die Variablen der Shell an.Eine Teilmenge der Shell-Variablen sind die Umgebungsvariablen, deren Werte entweder beim Starten der Shell von der Umgebung geerbt oder durch Setzen des
export
Attributs auf einen gültigen Namen erstellt werden.quelle
set
alle Parameter inzsh
(nicht $ 1, $ 2 ..., sondern $ *, $ @) und die Funktionen in bash und bosh angezeigt werden. Einige Shells wie ksh93 und ältere Versionen von Dash-Ausgabevariablen, die nicht Shell-Variablen zugeordnet wurden. (env 1=foo ksh -c set
würde drucken1=foo
)Umgebungsvariablen vs Positionsparameter
Bevor wir mit der Erörterung
$INTEGER
von Variablentypen beginnen, müssen wir verstehen, was sie wirklich sind und wie sie sich von Umgebungsvariablen unterscheiden. Variablen, wie sie als$INTEGER
Positionsparameter bezeichnet werden. Dies ist im POSIX-Standard (Portable Operating System Interface), Abschnitt 2.1 (Hervorhebung) beschrieben:Im Gegensatz dazu sind Variablen wie
$HOME
und$PATH
Umgebungsvariablen. Ihre Definition ist in Abschnitt 8 der Norm beschrieben :Beachten Sie deren Beschreibung. Positionsparameter sollen vor einem Befehl erscheinen, dh
command positional_arg_1 positional_arg_2...
. Sie sollen vom Benutzer bereitgestellt werden, um dem Befehl mitzuteilen, was speziell zu tun ist. Wenn Sie dies tunecho 'Hello' 'World'
, werden die ZeichenfolgenHello
undWorld
ausgedruckt, da dies Positionsparameter fürecho
die Dinge sind, mit denen Sie arbeiten möchtenecho
. Undecho
ist so aufgebaut, dass es Positionsparameter als zu druckende Zeichenfolgen versteht (es sei denn, sie sind eines der optionalen Flags wie-n
). Wenn Sie dies mit einem anderen Befehl tun, wird möglicherweise nicht verstanden, wasHello
undWorld
liegt daran, dass es vielleicht eine nummer erwartet. Beachten Sie, dass Positionsparameter nicht "geerbt" werden - ein untergeordneter Prozess kennt die Positionsparameter des übergeordneten Prozesses nur, wenn sie ausdrücklich an den untergeordneten Prozess übergeben werden. Häufig werden Positionsparameter mit Wrapper-Skripten übergeben. Diese prüfen möglicherweise, ob bereits ein Befehl vorhanden ist, oder fügen dem aufzurufenden realen Befehl zusätzliche Positionsparameter hinzu.Im Gegensatz dazu sollen Umgebungsvariablen mehrere Programme beeinflussen. Sie sind Umgebungsvariablen , da sie außerhalb des Programms selbst festgelegt sind (mehr dazu weiter unten). Bestimmte Umgebungsvariablen wie
HOME
oderPATH
haben ein bestimmtes Format, eine bestimmte Bedeutung und bedeuten für jedes Programm dasselbe.HOME
Variable bedeutet dasselbe für ein externes Dienstprogramm wie/usr/bin/find
oder Ihre Shell (und folglich für ein Skript) - es ist das Ausgangsverzeichnis des Benutzernamens, unter dem der Prozess ausgeführt wird. Beachten Sie, dass Umgebungsvariablen zum Beispiel verwendet werden können, um ein bestimmtes Befehlsverhalten zu berücksichtigenUID
Die Umgebungsvariable kann verwendet werden, um zu überprüfen, ob das Skript mit Root-Rechten ausgeführt wird oder nicht, und entsprechend zu bestimmten Aktionen zu verzweigen. Umgebungsvariablen sind vererbbar - untergeordnete Prozesse erhalten eine Kopie der übergeordneten Umgebung. Siehe auch Wenn Prozesse die Umgebung des übergeordneten Elements erben, warum müssen wir exportieren?Kurz gesagt, der Hauptunterschied besteht darin, dass Umgebungsvariablen außerhalb des Befehls festgelegt werden und (normalerweise) nicht variiert werden sollen, während Positionsparameter Dinge sind, die vom Befehl verarbeitet werden sollen und sich ändern.
Nicht nur Shell-Konzepte
Was ich aus Kommentaren mitbekommen habe, ist, dass Sie Terminal und Shell vertauschen, und ich würde Ihnen wirklich empfehlen, über echte Terminals zu lesen , die früher physische Geräte waren. Heutzutage ist das "Terminal", auf das wir uns normalerweise beziehen, dieses Fenster mit schwarzem Hintergrund und grünem Text eigentlich Software, ein Prozess. Terminal ist ein Programm, das eine Shell ausführt, während Shell auch ein Programm ist, das jedoch das liest, was Sie eingeben, um es auszuführen (dh, wenn es sich um eine interaktive Shell handelt; nicht interaktive Shells sind Skripte und
sh -c 'echo foo'
Arten von Aufrufen). Mehr zu Muscheln hier .Dies ist eine wichtige Unterscheidung, aber auch wichtig zu erkennen, dass das Terminal ein Programm ist und daher dieselben Umgebungsregeln und Positionsparameter einhält. Ihre
gnome-terminal
wann Blick auf Ihre gestartetSHELL
Umgebungsvariable, und laichen die entsprechende Standard - Shell für Sie, wenn Sie mit einem anderen Befehl angeben-e
. Sagen wir , ich meine Standard - Shell geändertksh
- gnome-terminal wird dann laichenksh
stattbash
. Dies ist auch ein Beispiel dafür, wie die Umgebung von Programmen verwendet wird. Wenn ich ausdrücklich sagen ,gnome-terminal
mit-e
bestimmt Shell auszuführen - es wird es tun, aber es wird nicht dauerhaft sein. Im Gegensatz dazu soll die Umgebung größtenteils unverändert bleiben (dazu später mehr).Wie Sie sehen können, sind Umgebungsvariablen und Positionsvariablen beide Eigenschaften eines Prozesses / Befehls und nicht nur eine Shell. Wenn es um Shell-Skripte geht, folgen sie auch dem Modell, das von der Programmiersprache C festgelegt wurde. Nehmen wir zum Beispiel die C-
main
Funktion, die normalerweise so aussieht, wo
argc
ist die Anzahl der Befehlszeilenargumente undargv
ist effektiv Array von Befehlszeilenparametern, und dann gibt es eineenviron
Funktion (unter Linuxman -e 7 environ
), um auf Dinge wie den Home-Verzeichnispfad des Benutzers, eine Liste von Verzeichnissen zuzugreifen, inPATH
denen wir nach ausführbaren Dateien suchen können, usw. In ähnlicher Weise werden auch Shell-Skripte modelliert. In Schale Terminologie haben wir Positionsparameter$1
,$2
usw., während die$#
Anzahl der Positionsparameter ist. Was ist$0
? Das ist der Name der ausführbaren Datei selbst, die ebenfalls aus der Programmiersprache C abgeleitet ist -argv[0]
wäre der Name Ihrer ausführbaren C-Datei. Dies gilt für die meisten Programmier- und Skriptsprachen .Interaktive vs nicht interaktive Shells
Eines der Dinge, die ich bereits angedeutet habe, ist die Unterscheidung zwischen interaktiven und nicht interaktiven Shells . Die Eingabeaufforderung, in der Sie Befehle eingeben - das ist interaktiv, es interagiert mit dem Benutzer. Im Gegensatz dazu, wenn Sie ein Shell-Skript haben oder es
bash -c''
nicht interaktiv ausführen .Und hier wird Unterscheidung wichtig. Die Shell, die Sie bereits ausführen, ist ein Prozess, der mit Positionsparametern erzeugt wurde (für die
bash
Anmeldeshell ist dies einer "... dessen erstes Zeichen des Arguments Null ein - ist oder einer, der mit der Option --login gestartet wurde" ( Referenz ). )Im Gegensatz dazu Skripte und Muscheln mit ins Leben gerufen
-c
Option nutzen können$1
und$2
Argumente. Zum Beispiel,Beachten Sie, dass ich dort auch verwendet habe
sh
, weil eine kleine Eigenheit der-c
Option darin besteht, den ersten Positionsparameter zu nehmen und ihm zuzuweisen$0
, im Gegensatz dazu, dass es normalerweise ein Name des Programms ist.Eine andere wichtige Sache ist, dass Positionsparameter das sind, was ich "framable" nenne. Beachten Sie, wie wir zuerst
bash
mit eigenen Positionsparametern gestartet haben , aber diese Positionsparameter wurden zu Parametern fürecho
undstat
. Und jedes Programm versteht es auf seine Weise. Wenn wirstat
eine Zeichenfolge angebenHello World
und keine Datei vorhandenHello World
ist, wird ein Fehler ausgegeben.bash
behandelt es wie eine einfache Zeichenfolge,stat
erwartet jedoch, dass es sich bei dieser Zeichenfolge um einen vorhandenen Dateinamen handelt. Im Gegensatz dazu stimmen alle Programme darin überein, dass die UmgebungsvariableHOME
ein Verzeichnis ist (es sei denn, der Programmierer hat es in unvernünftiger Weise codiert).Können wir mit Umgebungsvariablen und Positionsparametern herumspielen?
Technisch können wir mit beiden herumspielen, aber wir sollten nicht mit Umgebungsvariablen herumspielen, während wir oft Positionsparameter bereitstellen müssen. Wir können Befehle in der Shell ausführen, indem wir eine Variable voranstellen, zum Beispiel:
Wir können Variablen auch einfach
export variable=value
aus der Shell oder dem Skript heraus in die Umgebung einfügen . Oder wir können einen Befehl mit völlig leerer Umgebung mit ausführenenv -c command arg1 arg2
. In der Regel wird jedoch nicht empfohlen, mit der Umgebung herumzuspielen, insbesondere wenn Sie Variablen in Großbuchstaben verwenden oder bereits vorhandene Umgebungsvariablen überschreiben. Beachten Sie, dass dies empfohlen wird, obwohl dies kein Standard ist.Bei Positionsparametern ist die Art und Weise der Einstellung offensichtlich. Stellen Sie sie einfach vor den Befehl, aber es gibt auch Möglichkeiten, sie auf andere Weise einzustellen und die Liste dieser Parameter über den
shift
Befehl zu ändern .Zusammenfassend ist der Zweck dieser beiden unterschiedlich, und sie existieren aus einem Grund. Ich hoffe, die Leute haben einen Einblick in diese Antwort erhalten, und es hat Spaß gemacht, sie so zu lesen, wie es für mich war, diese Antwort zu schreiben.
Hinweis zum Befehl set
Der
set
Befehl verhält sich laut Handbuch wie folgt (aus Bash-Handbuch, Hervorhebung hinzugefügt):Mit anderen Worten, es
set
werden spezifische Variablen für die Shell betrachtet, von denen sich einige zum Beispiel zufällig in der Umgebung befindenHOME
. Im Gegensatz dazu mögenenv
undprintenv
betrachten Befehle die tatsächliche Umgebungsvariable, mit der ein Befehl ausgeführt wird. Siehe auch das .quelle
1="foo"
, darauf hingewiesen habe, dass man so etwas nicht kann, aber später stellte ich fest, dass nach POSIX-Definition ein "Wort" (das ist ein Name eines Objekts wie eine Variable oder eine Funktion) nicht beginnen kann mit einer Ziffer (siehe eine Frage, die ich zum Thema gestellt habe ). Positionsparameter sind offensichtlich eine Ausnahme von dieser Regel.$1
,$2
und zwar mitset
Befehlen, um die/bin/sh
Einschränkung zu umgehen , dass keine Arrays vorhanden sind. Vielen Dank, dass Sie mich darauf aufmerksam gemacht haben. Ich werde die Antwort in den nächsten Tagen auch bearbeiten, da es ein bisschen mehr Glanz und ein Update braucht.conda
, wenn Sie laufensource conda/bin/activate
, es prüft , ob$1
,$2
etc. eingestellt werden , um zu bestimmen , ob sie als Skript mit Argumenten oder nicht ausgeführt wurde. Dies führt dazu, dass Systeme aus irgendeinem Grund nicht mehr funktionieren, auf denen diese in der interaktiven Umgebung eingestellt sind. Ich hoffe herauszufinden, ob dieses nicht standardmäßige Verhalten ein Fehler im System zum Festlegen dieser Variablen in der interaktiven Umgebung oder im Programm ist, mit dessen Hilfe festgestellt werden kann, ob sie als Skript ausgeführt wurden.conda
Entwickler oder an den ursprünglichen Autor eines solchen Skripts senden , da die Überprüfung auf${N}
Parameter definitiv der falsche Weg ist. Es gibt Fragen zum gleichen Thema hier und hier , und mehr oder weniger üblich ist es, zu überprüfen, ob${0}
es sich um den gleichenbash
Die
$1, $2, $3, ..., ${10}, ${11}
Variablen werden als Positionsparameter bezeichnet und werden im Abschnitt Bash-Handbuch behandelt3.4.1
In Bezug auf
$?
und$0
werden diese speziellen Parameter im nächsten Abschnitt behandelt3.4.2
quelle
$1
,$2
... sind Positionsparameter , keine Variablen, geschweige denn Umgebungsvariablen.In Bourne-Shell wie Terminologie
$something
heißt Parametererweiterung (auch Abdeckungen${something#pattern}
und mehr in einigen Muscheln wie${array[x]}
,${param:offset}
,${x:|y}
und viele weitere Expansion Operatoren).Es gibt verschiedene Arten von Parametern:
$foo
,$PATH
$1
,$2
... die Argumente, die Ihr Skript erhalten hat)$0
,$-
,$#
,$*
,$@
,$$
,$!
,$?
...Variablennamen in Bourne-ähnlichen Shells müssen mit einem alphabetischen Zeichen beginnen (eines, das vom Gebietsschema erkannt wird oder je nach Shell auf a-zA-Z beschränkt ist) und unterstrichen und von null oder mehr alphanumerischen Zeichen oder Unterstrichen gefolgt werden.
Je nach Shell können Variablen unterschiedliche Typen (Skalar, Array, Hash) oder bestimmte Attribute (schreibgeschützt, exportiert, Kleinbuchstaben ...) haben.
Einige dieser Variablen werden von der Shell erstellt oder haben besondere Bedeutung für die Shell (wie
$OPTIND
,$IFS
,$_
...)Shell-Variablen mit dem Export- Attribut werden automatisch als Umgebungsvariablen in die Befehle exportiert , die die Shell ausführt.
Umgebungsvariable ist ein von Shell-Variablen getrenntes Konzept. Das Exportieren einer Shell-Variablen ist nicht die einzige Möglichkeit, eine Umgebungsvariable an die Ausführung eines Befehls zu übergeben.
Übergibt eine
VAR
Umgebungsvariable an denprintenv
Befehl (von dem wir sagen, dass er seinen Inhalt drucken soll). Sie können jedoch auch Folgendes tun:oder:
zum Beispiel.
Umgebungsvariablen können einen beliebigen Namen haben (können ein beliebiges Zeichen enthalten, aber
=
auch leer sein). Es ist keine gute Idee, einer Umgebungsvariablen einen Namen zu geben, der nicht mit dem Namen einer Bourne-ähnlichen Shell-Variablen kompatibel ist, aber es ist möglich:Shells ordnen die Umgebungsvariablen, die sie empfangen , nur für diejenigen Umgebungsvariablen Shell-Variablen zu, deren Name gültige Shell-Variablen sind (und ignorieren in einigen Shells einige spezielle Variablen wie
$IFS
).So, während Sie eine
1
Umgebungsvariable an einen Befehl übergeben können:Das bedeutet nicht, dass der Aufruf einer Shell mit dieser Umgebungsvariablen den Wert des
$1
Parameters festlegen würde :quelle
Nein, das sind Parameter des Skripts. Zum Beispiel, wenn Sie Ihr Skript wie folgt aufrufen:
Innerhalb des Skripts stehen diese Parameter dann zur Verfügung als
und $ 0 ist der Name des Skripts.
Wenn Sie sich also außerhalb des Skripts befinden, sind diese Variablen nicht verfügbar (mit Ausnahme von $ 0, die / bin / bash - die Shell selbst - anzeigt).
quelle
$0
zeigt auf Ihren aktuellen Terminal-Prozess (wahrscheinlich Bash) und$?
ist einfach der Exit-Code des letzten Prozesses.gnome-terminal
mit Argumenten (gnome-terminal Hello World
) auszuführen . Ich konnte sehen$0
, aber ich konnte nicht sehen$1
und$2
.