Ich habe ein ziemlich einfaches Skript, das ungefähr so ist:
#!/bin/bash
VAR1="$1"
MOREF='sudo run command against $VAR1 | grep name | cut -c7-'
echo $MOREF
Wenn ich dieses Skript über die Befehlszeile ausführe und die Argumente übergebe, bekomme ich keine Ausgabe. Wenn ich jedoch die Befehle innerhalb der $MOREF
Variable kann ich ausgeben.
Ich würde gerne wissen, wie man die Ergebnisse eines Befehls, der innerhalb eines Skripts ausgeführt werden muss, in einer Variablen speichern und diese Variable dann auf dem Bildschirm ausgeben kann.
Zusätzlich zu den Backticks können Sie verwenden $()
, die ich leichter zu lesen finde, und das Nesting ermöglicht.
OUTPUT="$(ls -1)"
echo "${OUTPUT}"
Zitieren ("
) ist wichtig, um mehrzeilige Werte zu erhalten.
Aktualisieren (2018): Der richtige Weg ist
$(sudo run command)
Sie verwenden die falsche Art von Apostroph. Du brauchst `
nicht '
. Dieser Charakter wird "Backticks" (oder "Grabakzent") genannt.
So was:
#!/bin/bash
VAR1="$1"
VAR2="$2"
MOREF=`sudo run command against "$VAR1" | grep name | cut -c7-`
echo "$MOREF"
Wie Sie bereits angedeutet haben, sollten Sie "Backticks" verwenden.
Die vorgeschlagene Alternative $(command)
funktioniert auch, und es ist auch einfacher zu lesen,
aber beachte, dass es nur mit Bash- oder Kornschalen (und davon abgeleiteten Schalen) gültig ist,
Wenn also Ihre Skripte auf verschiedenen Unix-Systemen wirklich portabel sein müssen, sollten Sie die alte Backtick-Notation bevorzugen.
Ich kenne drei Möglichkeiten:
1) Funktionen sind für solche Aufgaben geeignet:
func (){
ls -l
}
Rufen Sie es an, indem Sie sagen func
2) Auch eine andere geeignete Lösung könnte eval sein:
var="ls -l"
eval $var
3) Der dritte verwendet Variablen direkt:
var=$(ls -l)
OR
var=`ls -l`
Sie können die Ausgabe der dritten Lösung in guter Weise erhalten:
echo "$var"
und auch auf böse Weise:
echo $var
Etwas bash Tricks, mit denen ich Variablen aus Befehlen setze
2. Edit 2018-02-12: Einen speziellen Weg hinzufügen, siehe ganz unten!
2018-01-25 Bearbeiten: Beispielfunktion hinzufügen (zum Füllen von Variablen über die Plattennutzung)
Erster einfacher alter und kompatibler Weg
myPi=`echo '4*a(1)' | bc -l`
echo $myPi
3.14159265358979323844
Meist kompatibel, zweiter Weg
Da die Verschachtelung schwer werden könnte, wurde dafür eine Klammer eingefügt
myPi=$(bc -l <<<'4*a(1)')
Verschachteltes Beispiel:
SysStarted=$(date -d "$(ps ho lstart 1)" +%s)
echo $SysStarted
1480656334
mehr als eine Variable lesen (mit Bashismen)
df -k /
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/dm-0 999320 529020 401488 57% /
Wenn ich nur will Benutzt Wert:
array=($(df -k /))
Du könntest sehen Array Variable:
declare -p array
declare -a array='([0]="Filesystem" [1]="1K-blocks" [2]="Used" [3]="Available" [
4]="Use%" [5]="Mounted" [6]="on" [7]="/dev/dm-0" [8]="999320" [9]="529020" [10]=
"401488" [11]="57%" [12]="/")'
Dann:
echo ${array[9]}
529020
Aber ich bevorzuge das:
{ read foo ; read filesystem size used avail prct mountpoint ; } < <(df -k /)
echo $used
529020
1 read foo
wird nur überspringen Kopfzeile (Variable $foo
wird etwas wie enthalten Filesystem 1K-blocks Used Available Use% Mounted on
)
Beispielfunktion zum Auffüllen einiger Variablen:
#!/bin/bash
declare free=0 total=0 used=0
getDiskStat() {
local foo
{
read foo
read foo total used free foo
} < <(
df -k ${1:-/}
)
}
getDiskStat $1
echo $total $used $free
Kein: declare
Zeile ist nicht erforderlich, nur für die Lesbarkeit.
Über sudo cmd | grep ... | cut ...
shell=$(cat /etc/passwd | grep $USER | cut -d : -f 7)
echo $shell
/bin/bash
(Bitte vermeiden Sie nutzlos cat
! Das ist also nur 1 Gabel weniger:
shell=$(grep $USER </etc/passwd | cut -d : -f 7)
Alle Rohre (|
) impliziert Gabeln. Wo ein anderer Prozess ausgeführt werden muss, Zugriff auf Datenträger, Bibliothekenaufrufe usw.
Also benutzen sed
Für Beispiel wird der Unterprozess auf nur einen beschränkt Gabel:
shell=$(sed </etc/passwd "s/^$USER:.*://p;d")
echo $shell
Und mit Bashismen:
Aber für viele Aktionen, meist auf kleinen Dateien, bash könnte den Job selbst erledigen:
while IFS=: read -a line ; do
[ "$line" = "$USER" ] && shell=${line[6]}
done </etc/passwd
echo $shell
/bin/bash
oder
while IFS=: read loginname encpass uid gid fullname home shell;do
[ "$loginname" = "$USER" ] && break
done </etc/passwd
echo $shell $loginname ...
Weiter gehen variable Aufteilung...
Schau dir meine Antwort an Wie spalte ich eine Zeichenfolge auf einem Trennzeichen in Bash?
Alternative: Reduzieren Gabeln durch Verwendung lang andauernder Aufgaben im Hintergrund
2. Bearbeitung 2018-02-12:
Um mehrere Gabeln wie zu verhindern
myPi=$(bc -l <<<'4*a(1)'
myRay=12
myCirc=$(bc -l <<<" 2 * $myPi * $myRay ")
oder
myStarted=$(date -d "$(ps ho lstart 1)" +%s)
mySessStart=$(date -d "$(ps ho lstart $$)" +%s)
Und weil date
und bc
könnte klappen Zeile für Zeile:
bc -l <<<$'3*4\n5*6'
12
30
date -f - +%s < <(ps ho lstart 1 $$)
1516030449
1517853288
Wir könnten es gebrauchen lange läuft Hintergrundprozess, um Jobs wiederholt zu erstellen, ohne neue initiieren zu müssen Gabel für jede Anfrage:
mkfifo /tmp/myFifoForBc
exec 5> >(bc -l >/tmp/myFifoForBc)
exec 6</tmp/myFifoForBc
rm /tmp/myFifoForBc
(natürlich, FD 5
und 6
muss ungenutzt sein!) ... Von dort aus könntest du diesen Prozess benutzen:
echo "3*4" >&5
read -u 6 foo
echo $foo
12
echo >&5 "pi=4*a(1)"
echo >&5 "2*pi*12"
read -u 6 foo
echo $foo
75.39822368615503772256
In eine Funktion newConnector
Du kannst meine finden newConnector
Funktion an GitHub.Com oder weiter meine eigene Seite (Nota auf Github, es gibt zwei Dateien, auf meiner Website sind Funktion und Demo in 1 Datei gebündelt, die zur Verwendung bereitgestellt werden kann oder einfach nur zur Demo laufen kann)
Probe:
. shell_connector.sh
tty
/dev/pts/20
ps --tty pts/20 fw
PID TTY STAT TIME COMMAND
29019 pts/20 Ss 0:00 bash
30745 pts/20 R+ 0:00 \_ ps --tty pts/20 fw
newConnector /usr/bin/bc "-l" '3*4' 12
ps --tty pts/20 fw
PID TTY STAT TIME COMMAND
29019 pts/20 Ss 0:00 bash
30944 pts/20 S 0:00 \_ /usr/bin/bc -l
30952 pts/20 R+ 0:00 \_ ps --tty pts/20 fw
declare -p PI
bash: declare: PI: not found
myBc '4*a(1)' PI
declare -p PI
declare -- PI="3.14159265358979323844"
Die Funktion myBc
Verwenden Sie die Hintergrundaufgabe mit einfacher Syntax und für Datum:
newConnector /bin/date '-f - +%s' @0 0
myDate '2000-01-01'
946681200
myDate "$(ps ho lstart 1)" boottime
myDate now now ; read utm idl </proc/uptime
myBc "$now-$boottime" uptime
printf "%s\n" ${utm%%.*} $uptime
42134906
42134906
ps --tty pts/20 fw
PID TTY STAT TIME COMMAND
29019 pts/20 Ss 0:00 bash
30944 pts/20 S 0:00 \_ /usr/bin/bc -l
32615 pts/20 S 0:00 \_ /bin/date -f - +%s
3162 pts/20 R+ 0:00 \_ ps --tty pts/20 fw
Von dort aus, wenn Sie einen Hintergrundprozess beenden möchten, müssen Sie nur seine schließen fd:
eval "exec $DATEOUT>&-"
eval "exec $DATEIN>&-"
ps --tty pts/20 fw
PID TTY STAT TIME COMMAND
4936 pts/20 Ss 0:00 bash
5256 pts/20 S 0:00 \_ /usr/bin/bc -l
6358 pts/20 R+ 0:00 \_ ps --tty pts/20 fw
das wird nicht benötigt, weil alle fd schließen, wenn der Hauptprozess beendet ist.
Wenn Sie dies mit mehrzeiligen / mehreren Befehlen tun wollen, können Sie dies tun:
output=$( bash <<EOF
#multiline/multiple command/s
EOF
)
Oder:
output=$(
#multiline/multiple command/s
)
Beispiel:
#!/bin/bash
output="$( bash <<EOF
echo first
echo second
echo third
EOF
)"
echo "$output"
Ausgabe:
first
second
third
Verwenden Heredoc Sie können die Dinge ziemlich einfach vereinfachen, indem Sie Ihren langen einzeiligen Code in multiline zerlegen. Ein anderes Beispiel:
output="$( ssh -p $port $user@$domain <<EOF
#breakdown your long ssh command into multiline here.
EOF
)"
Stellen Sie sicher, dass Sie eine Variable gesetzt haben Kein Platz vor und / oder nach dem = Schild. Buchstäblich verbrachte eine Stunde versucht, dies herauszufinden, versuchen alle Arten von Lösungen! Das ist nicht cool.
Richtig:
WTFF=`echo "stuff"`
echo "Example: $WTFF"
Wird versagen mit Fehler: (Sachen: nicht gefunden oder ähnlich)
WTFF= `echo "stuff"`
echo "Example: $WTFF"
Sie können Back-Ticks (auch Akzentgräber genannt) oder $()
.
Wie as-
OUTPUT=$(x+2);
OUTPUT=`x+2`;
Beides hat den gleichen Effekt. Aber OUTPUT = $ (x + 2) ist lesbarer und die letzte.
Dies ist eine andere Möglichkeit, die Sie mit einigen Texteditoren verwenden können, die nicht jeden komplizierten Code, den Sie erstellen, richtig hervorheben können.
read -r -d '' str < <(cat somefile.txt)
echo "${#str}"
echo "$str"