Một số thủ thuật Bash tôi sử dụng để đặt biến từ các lệnh
Chỉnh sửa lần 2 2018-02-12: Đã thêm một cách khác, tìm kiếm ở dưới cùng của điều này cho các nhiệm vụ dài hạn !
2018-01-25 Chỉnh sửa: đã thêm một hàm mẫu (để điền các biến về việc sử dụng đĩa)
Cách đầu tiên đơn giản, cũ và tương thích
myPi=`echo '4*a(1)' | bc -l`
echo $myPi
3.14159265358979323844
Chủ yếu là tương thích, cách thứ hai
Khi lồng có thể trở nên nặng nề, dấu ngoặc đơn đã được thực hiện cho điều này
myPi=$(bc -l <<<'4*a(1)')
Mẫu lồng nhau:
SysStarted=$(date -d "$(ps ho lstart 1)" +%s)
echo $SysStarted
1480656334
Đọc nhiều hơn một biến số (với Bashism )
df -k /
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/dm-0 999320 529020 401488 57% /
Nếu tôi chỉ muốn một giá trị được sử dụng :
array=($(df -k /))
bạn có thể thấy một biến mảng :
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]="/")'
Sau đó:
echo ${array[9]}
529020
Nhưng tôi thích điều này:
{ read foo ; read filesystem size using avail prct mountpoint ; } < <(df -k /)
echo $using
529020
Đầu tiên read foo
sẽ chỉ bỏ qua dòng tiêu đề, nhưng chỉ trong một lệnh, bạn sẽ điền 7 biến khác nhau :
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"
Hoặc thậm chí:
{ 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")
... cũng sẽ làm việc với các mảng kết hợp :read foo disk[total] disk[used] ...
Hàm mẫu để điền một số biến:
#!/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: declare
dòng không bắt buộc, chỉ để dễ đọc.
Trong khoảng sudo cmd | grep ... | cut ...
shell=$(cat /etc/passwd | grep $USER | cut -d : -f 7)
echo $shell
/bin/bash
(Xin vui lòng tránh vô dụng cat
! Vì vậy, đây chỉ là một ngã ba ít hơn:
shell=$(grep $USER </etc/passwd | cut -d : -f 7)
Tất cả các ống ( |
) ngụ ý dĩa. Trường hợp một quá trình khác phải được chạy, truy cập đĩa, thư viện gọi và như vậy.
Vì vậy, sử dụng sed
cho mẫu, sẽ giới hạn quy trình con chỉ trong một ngã ba :
shell=$(sed </etc/passwd "s/^$USER:.*://p;d")
echo $shell
Và với Bashism :
Nhưng đối với nhiều hành động, chủ yếu là trên các tệp nhỏ, Bash có thể tự thực hiện công việc:
while IFS=: read -a line ; do
[ "$line" = "$USER" ] && shell=${line[6]}
done </etc/passwd
echo $shell
/bin/bash
hoặc là
while IFS=: read loginname encpass uid gid fullname home shell;do
[ "$loginname" = "$USER" ] && break
done </etc/passwd
echo $shell $loginname ...
Đi xa hơn về việc chia nhỏ biến ...
Hãy xem câu trả lời của tôi về Làm thế nào để tôi chia một chuỗi trên một dấu phân cách trong Bash?
Thay thế: giảm dĩa bằng cách sử dụng các tác vụ chạy dài nền
Chỉnh sửa lần 2 2018-02-12:
Để ngăn chặn nhiều dĩa như
myPi=$(bc -l <<<'4*a(1)'
myRay=12
myCirc=$(bc -l <<<" 2 * $myPi * $myRay ")
hoặc là
myStarted=$(date -d "$(ps ho lstart 1)" +%s)
mySessStart=$(date -d "$(ps ho lstart $$)" +%s)
Điều này làm việc tốt, nhưng chạy nhiều dĩa là nặng và chậm.
Và các lệnh như date
và bc
có thể thực hiện nhiều hoạt động, từng dòng một !!
Xem:
bc -l <<<$'3*4\n5*6'
12
30
date -f - +%s < <(ps ho lstart 1 $$)
1516030449
1517853288
Vì vậy, chúng tôi có thể sử dụng một quá trình nền chạy dài để thực hiện nhiều công việc, mà không phải bắt đầu một ngã ba mới cho mỗi yêu cầu.
Chúng tôi chỉ cần một số mô tả tập tin và fifos để làm điều này đúng:
mkfifo /tmp/myFifoForBc
exec 5> >(bc -l >/tmp/myFifoForBc)
exec 6</tmp/myFifoForBc
rm /tmp/myFifoForBc
(Tất nhiên, FD 5
và 6
phải không được sử dụng!) ... Từ đó, bạn có thể sử dụng quy trình này bằng cách:
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
Vào một chức năng newConnector
Bạn có thể tìm thấy newConnector
chức năng của tôi trên GitHub.Com hoặc trên trang web của riêng tôi (Lưu ý trên GitHub: có hai tệp trên trang web của tôi. Chức năng và bản demo được gói vào một tệp có thể được lấy nguồn để sử dụng hoặc chỉ chạy để dùng thử.)
Mẫu vật:
. 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"
Hàm myBc
cho phép bạn sử dụng tác vụ nền với cú pháp đơn giản và cho ngày:
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
Từ đó, nếu bạn muốn kết thúc một trong các tiến trình nền, bạn chỉ cần đóng fd của nó :
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
không cần thiết, bởi vì tất cả fd đóng khi quá trình chính kết thúc.