Alcuni trucchi Bash che uso per impostare variabili dai comandi
2a modifica 2018-02-12: aggiunto un altro modo, cerca in fondo per attività di lunga durata !
25/01/2018 Modifica: aggiunta una funzione di esempio (per popolare le variabili sull'uso del disco)
Primo modo semplice, vecchio e compatibile
myPi=`echo '4*a(1)' | bc -l`
echo $myPi
3.14159265358979323844
Per lo più compatibile, secondo modo
Poiché la nidificazione potrebbe diventare pesante, è stata implementata la parentesi per questo
myPi=$(bc -l <<<'4*a(1)')
Campione nidificato:
SysStarted=$(date -d "$(ps ho lstart 1)" +%s)
echo $SysStarted
1480656334
Leggere più di una variabile (con Bashisms )
df -k /
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/dm-0 999320 529020 401488 57% /
Se voglio solo un valore usato :
array=($(df -k /))
potresti vedere una variabile array :
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]="/")'
Poi:
echo ${array[9]}
529020
Ma preferisco questo:
{ read foo ; read filesystem size using avail prct mountpoint ; } < <(df -k /)
echo $using
529020
Il primo read foo
sarà solo saltare riga di intestazione, ma in un solo comando, verrà popolare 7 diverse variabili:
declare -p avail filesystem foo mountpoint prct size using
declare -- avail="401488"
declare -- filesystem="/dev/dm-0"
declare -- foo="Filesystem 1K-blocks Used Available Use% Mounted on"
declare -- mountpoint="/"
declare -- prct="57%"
declare -- size="999320"
declare -- using="529020"
O anche:
{ read foo ; read filesystem dsk[{6,2,9}] prct mountpoint ; } < <(df -k /)
declare -p mountpoint dsk
declare -- mountpoint="/"
declare -a dsk=([2]="529020" [6]="999320" [9]="401488")
... funzionerà anche con array associativi :read foo disk[total] disk[used] ...
Funzione di esempio per popolare alcune variabili:
#!/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
Nota: la declare
riga non è richiesta, solo per leggibilità.
Di sudo cmd | grep ... | cut ...
shell=$(cat /etc/passwd | grep $USER | cut -d : -f 7)
echo $shell
/bin/bash
(Per favore, evita inutili cat
! Quindi questo è solo un fork in meno:
shell=$(grep $USER </etc/passwd | cut -d : -f 7)
Tutti i tubi ( |
) implicano le forcelle. Dove è necessario eseguire un altro processo, accedere al disco, chiamare le librerie e così via.
Quindi, usando sed
per esempio, limiterai il sottoprocesso a un solo fork :
shell=$(sed </etc/passwd "s/^$USER:.*://p;d")
echo $shell
E con Bashisms :
Ma per molte azioni, principalmente su file di piccole dimensioni, Bash potrebbe fare il lavoro da solo:
while IFS=: read -a line ; do
[ "$line" = "$USER" ] && shell=${line[6]}
done </etc/passwd
echo $shell
/bin/bash
o
while IFS=: read loginname encpass uid gid fullname home shell;do
[ "$loginname" = "$USER" ] && break
done </etc/passwd
echo $shell $loginname ...
Andare oltre sulla suddivisione variabile ...
Dai un'occhiata alla mia risposta a Come divido una stringa su un delimitatore in Bash?
Alternativa: ridurre le forche utilizzando attività di lunga durata in background
2a modifica 2018-02-12:
Al fine di prevenire più forcelle come
myPi=$(bc -l <<<'4*a(1)'
myRay=12
myCirc=$(bc -l <<<" 2 * $myPi * $myRay ")
o
myStarted=$(date -d "$(ps ho lstart 1)" +%s)
mySessStart=$(date -d "$(ps ho lstart $$)" +%s)
Funziona bene, ma eseguire molte forcelle è pesante e lento.
E comandi come date
e bc
potrebbero fare molte operazioni, riga per riga !!
Vedere:
bc -l <<<$'3*4\n5*6'
12
30
date -f - +%s < <(ps ho lstart 1 $$)
1516030449
1517853288
Quindi potremmo usare un lungo processo in background per fare molti lavori, senza dover avviare un nuovo fork per ogni richiesta.
Abbiamo solo bisogno di alcuni descrittori di file e quindici per farlo correttamente:
mkfifo /tmp/myFifoForBc
exec 5> >(bc -l >/tmp/myFifoForBc)
exec 6</tmp/myFifoForBc
rm /tmp/myFifoForBc
(Certo, FD 5
e 6
devono essere inutilizzati!) ... Da lì, è possibile utilizzare questo processo da:
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 una funzione newConnector
Puoi trovare la mia newConnector
funzione su GitHub.Com o sul mio sito (Nota su GitHub: ci sono due file sul mio sito. La funzione e la demo sono raggruppate in un file che può essere acquistato per l'uso o semplicemente eseguito per la demo.)
Campione:
. 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"
La funzione myBc
consente di utilizzare l'attività in background con una sintassi semplice e per data:
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
Da lì, se vuoi terminare uno dei processi in background, devi solo chiudere il suo 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
che non è necessario, perché tutti i fd si chiudono al termine del processo principale.