Ich versuche etwas Einfaches zu tun, bin mir aber nicht sicher, wie ich mein Ziel hier erreichen soll.
Ich versuche, die Werte USER, TTY und FROM zu extrahieren, die vom w
Befehl auf der Konsole angegeben werden. In bash versuche ich, diese Ausgabe zu übernehmen und diese Werte in ein mehrdimensionales Array (oder nur ein Array mit einem Leerzeichen) zu übertragen.
#!/bin/bash
w|awk '{if(NR > 2) print $1,$2,$3}' | while read line
do
USERS+=("$line")
echo ${#USERS[@]}
done
echo ${#USERS[@]}
Ich habe den Weg gefunden, die Werte zeilenweise in einem einzelnen Array einzulesen, aber ich kann den USERS-Array-Wert scheinbar nicht aus dem Bereich der while-Schleife herausholen. Es gibt die Werte 1,2,3,4 und dann 0 nach der Schleife aus. Jedes Beispiel, das ich lese, verwendet die Variable außerhalb des Gültigkeitsbereichs vollkommen in Ordnung, aber ich kann es nicht scheinen.
while read col1 col2 col3 _; do ...; done < <(w)
Antworten:
Ihr Hauptproblem besteht darin, dass der letzte Befehl in einer Pipeline wie alle anderen Befehle in der Pipeline in einer Subshell ausgeführt wird. Dies ist bei den meisten Schalen der Fall. ATT ksh und zsh sind Ausnahmen: Sie führen den letzten Befehl der Pipeline in der übergeordneten Shell aus.
Seit Bash 4.2 können Sie Bash anweisen, sich wie ksh und zsh zu verhalten, indem Sie die
lastpipe
Option festlegen .Alternativ können Sie die Prozessersetzung anstelle einer Pipe verwenden, sodass der
read
Befehl im Haupt-Shell-Prozess ausgeführt wird.Alternativ können Sie den portablen Ansatz verwenden, der in Shells funktioniert, die weder Prozesssusbtitution noch ksh / zsh-Verhalten aufweisen, wie z. B. Bourne, dash und pdksh. (Sie benötigen weiterhin (pd) ksh, bash oder zsh für Arrays.) Führen Sie alles aus, was die Daten aus der Pipeline innerhalb der Pipeline benötigt.
quelle
Mit
shopt -s lastpipe
können Sie den letzten Befehl einer Pipeline in die aktuelle Shell-Umgebung übernehmen. Das löst dein Problem. Ich denke, diese Funktion war nicht immer in Bash. Vermeiden Sie sie, wenn Sie weitgehend kompatiblen Code wünschen.Die kompatible Alternative:
quelle
USERS+=("$line")
stattUSERS[]="$line"
?+=
Notation in neueren Versionen von bash hinzugefügt wurde. Beide Befehle machen dasselbe.Bash-Arrays sind eindimensional. Wenn Sie geordnete separate Werte für jede Zeile beibehalten möchten, besteht eine Lösung darin, assoziative Arrays zu verwenden. Ein grobes Beispiel:
Seien Sie auch vorsichtig mit diesen Variablennamen in Großbuchstaben, da sie mit Umgebungsvariablen in Konflikt geraten können.
quelle
Für die Speicherung in Bash-Arrays ist die Verwendung eines anderen Trennzeichens als Leerzeichen häufig einfacher.
Sie können es dann beim Drucken aufteilen, z. B.:
quelle