Beberapa trik Bash yang saya gunakan untuk mengatur variabel dari perintah
Sunting ke-2 2018-02-12: Menambahkan cara yang berbeda, cari di bagian bawah ini untuk tugas yang sudah berjalan lama !
Edit 2018-01-25: menambahkan fungsi sampel (untuk mengisi variabel tentang penggunaan disk)
Pertama sederhana, lama, dan cara yang kompatibel
myPi=`echo '4*a(1)' | bc -l`
echo $myPi
3.14159265358979323844
Paling kompatibel, cara kedua
Karena bersarang bisa menjadi berat, kurung diimplementasikan untuk ini
myPi=$(bc -l <<<'4*a(1)')
Sampel bersarang:
SysStarted=$(date -d "$(ps ho lstart 1)" +%s)
echo $SysStarted
1480656334
Membaca lebih dari satu variabel (dengan Bashisms )
df -k /
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/dm-0 999320 529020 401488 57% /
Jika saya hanya ingin nilai yang digunakan :
array=($(df -k /))
Anda bisa melihat variabel 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]="/")'
Kemudian:
echo ${array[9]}
529020
Tapi saya lebih suka ini:
{ read foo ; read filesystem size using avail prct mountpoint ; } < <(df -k /)
echo $using
529020
Yang pertama read foo
hanya akan melewati baris tajuk, tetapi hanya dalam satu perintah, Anda akan mengisi 7 variabel yang berbeda :
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"
Atau bahkan:
{ 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")
... akan bekerja dengan array asosiatif juga:read foo disk[total] disk[used] ...
Fungsi sampel untuk mengisi beberapa variabel:
#!/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
Catatan: declare
baris tidak diperlukan, hanya agar mudah dibaca.
Tentang sudo cmd | grep ... | cut ...
shell=$(cat /etc/passwd | grep $USER | cut -d : -f 7)
echo $shell
/bin/bash
(Tolong hindari yang tidak berguna cat
! Jadi ini hanya satu fork less:
shell=$(grep $USER </etc/passwd | cut -d : -f 7)
Semua pipa ( |
) menyiratkan garpu. Di mana proses lain harus dijalankan, mengakses disk, pustaka panggilan, dan sebagainya.
Jadi gunakan sed
untuk sampel, akan membatasi subproses hanya satu garpu :
shell=$(sed </etc/passwd "s/^$USER:.*://p;d")
echo $shell
Dan dengan Bashisme :
Tetapi untuk banyak tindakan, kebanyakan pada file kecil, Bash dapat melakukan pekerjaan itu sendiri:
while IFS=: read -a line ; do
[ "$line" = "$USER" ] && shell=${line[6]}
done </etc/passwd
echo $shell
/bin/bash
atau
while IFS=: read loginname encpass uid gid fullname home shell;do
[ "$loginname" = "$USER" ] && break
done </etc/passwd
echo $shell $loginname ...
Lebih jauh tentang pemisahan variabel ...
Lihat jawaban saya untuk Bagaimana cara membagi string pada pembatas di Bash?
Alternatif: mengurangi garpu dengan menggunakan tugas yang sudah berjalan di latar belakang
Edit ke-2 2018-02-12:
Untuk mencegah beberapa garpu suka
myPi=$(bc -l <<<'4*a(1)'
myRay=12
myCirc=$(bc -l <<<" 2 * $myPi * $myRay ")
atau
myStarted=$(date -d "$(ps ho lstart 1)" +%s)
mySessStart=$(date -d "$(ps ho lstart $$)" +%s)
Ini berfungsi dengan baik, tetapi menjalankan banyak garpu berat dan lambat.
Dan perintah suka date
dan bc
bisa membuat banyak operasi, baris demi baris !!
Lihat:
bc -l <<<$'3*4\n5*6'
12
30
date -f - +%s < <(ps ho lstart 1 $$)
1516030449
1517853288
Jadi kami dapat menggunakan proses latar belakang yang berjalan lama untuk membuat banyak pekerjaan, tanpa harus memulai garpu baru untuk setiap permintaan.
Kami hanya perlu beberapa deskriptor dan fifos file untuk melakukan ini dengan benar:
mkfifo /tmp/myFifoForBc
exec 5> >(bc -l >/tmp/myFifoForBc)
exec 6</tmp/myFifoForBc
rm /tmp/myFifoForBc
(Tentu saja, FD 5
dan 6
harus tidak digunakan!) ... Dari sana, Anda dapat menggunakan proses ini dengan:
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
Menjadi suatu fungsi newConnector
Anda dapat menemukan newConnector
fungsi saya di GitHub.Com atau di situs saya sendiri (Catatan tentang GitHub: ada dua file di situs saya. Fungsi dan demo digabungkan menjadi satu file yang dapat bersumber untuk digunakan atau hanya dijalankan untuk demo.)
Sampel:
. 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"
Fungsi ini myBc
memungkinkan Anda menggunakan tugas latar belakang dengan sintaks sederhana, dan untuk tanggal:
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
Dari sana, jika Anda ingin mengakhiri salah satu proses latar belakang, Anda hanya perlu menutup 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
yang tidak diperlukan, karena semua fd tutup ketika proses utama selesai.