我创建了一个 bash 脚本,用于 Linux 中的图形栏,但是该脚本似乎产生了太多进程。
剧本:
#!/usr/bin/bash
executable="/usr/local/bin/bar"
monitor=${1:-0}
monitor_geometry=($(hc monitor_rect) $monitor)
x=${monitor_geometry[0]}
y=${monitor_geometry[1]}
panel_width=${monitor_geometry[2]}
panel_height=20
line_height=2
font="-*-terminesspowerline-medium-*-*-*-12-*-*-*-*-*-*-*"
bgcolor="#ff073642"
selbgcolor="#fffdf6e3"
selfgcolor="#ffeee8d5"
normfgcolor="#ff586e75"
urgentcolor="#ffdc322f"
separator=" "
icon_signal_max="|||"
icon_signal_med="||-"
icon_signal_min="|--"
icon_battery_charging="-"
icon_battery_discharging="x"
icon_arrow_up=""
# function declarations
hc() {
"${herbstclient_command[@]:-herbstclient}" "$@";
}
unique() {
awk '$0 != l { print; l=$0; fflush(); }' "$@"
}
get_datetime() {
{
while true; do
date +"datetime %a %d-%m-%Y (%V) %H:%M"
sleep 60
done
} | unique
}
get_power_status() {
{
while true; do
acpi_status=$(acpi --battery | cut -d' ' -f3 | sed 's/,//')
charge_percentage=$(acpi --battery | cut -d' ' -f4 | sed 's/%.*//')
if [[ $acpi_status ]]; then
if [[ "$acpi_status" == "Charging" ]]; then
status="$charge_percentage%%"
elif [[ "$acpi_status" == "Discharging" ]]; then
status="$charge_percentage%%"
elif [[ "$acpi_status" == "Unknown" ]]; then
status=""
fi
fi
if [[ "$charge_percentage" -le "20" ]]; then
status="%{F$urgentcolor}$status{F-}"
fi
echo "power_status $status"
sleep 1
done
} | unique
}
get_network_status() {
{
while true; do
wlan_ssid=$(iwgetid -r)
if [ -n $wlan_ssid ]; then
signal_strength=$(cat /proc/net/wireless | awk 'NR==3 {print $3}' | sed 's/\.//')
if [ "$signal_strength" -ge 65 ]; then
status="$wlan_ssid $icon_signal_max"
elif [ "$signal_strength" -lt 65 -a "$signal_strength" -ge 40 ]; then
status="$wlan_ssid $icon_signal_med"
else
status="$wlan_ssid $icon_signal_min"
fi
else
status=""
fi
echo "network_status $status"
sleep 1
done
} | unique
}
get_cpu_status() {
{
while true; do
no_cores=$(nproc)
loadavg=$(cat /proc/loadavg | awk '{print $1}')
if [ $(echo "$loadavg >= $no_cores" | bc) -ne 0 ]; then
status="%{F${urgentcolor}}${loadavg}%{F${normfgcolor}}"
else
status="$loadavg"
fi
echo "cpu_status $status"
sleep 1
done
} | unique
}
# register panel
hc pad $monitor $panel_height
# event multiplexer
{
get_datetime &
children[1]=$!
get_power_status &
children[2]=$!
get_network_status &
children[3]=$!
get_cpu_status &
children[4]=$!
hc --idle
for pid in ${children[@]}; do
kill $pid
done
} 2> /dev/null | {
tags=$(hc tag_status $monitor)
unset tags[${#tags[@]}-1]
visible=true
while true ; do
echo -n "%{c}"
for i in ${tags[@]}; do
case ${i:0:1} in
'.') # empty tag
echo -n "%{-uF${normfgcolor}}"
;;
'#') # current tag
echo -n "%{+u U${selfgcolor} F${selfgcolor}}"
;;
'+') # active on other monitor
echo -n "%{-uF$selfgcolor}"
;;
':') # tag with window(s)
echo -n "%{-uF$selfgcolor}"
;;
'!') # urgent tag
echo -n "%{-uF${urgentcolor}}"
;;
*)
echo -n "%{-uF${normfgcolor}}"
;;
esac
echo -n " ${i:1} "
done
# align left
echo -n "%{lF$selfgcolor}"
echo -n " "
echo -n "$power_status"
echo -n "$network_status"
echo -n "$cpu_status"
# align right
echo -n "%{r}"
echo -n "$datetime"
echo -n " "
echo
# wait for next event
read line || break
cmd=( $line )
# find out event origin
case ${cmd[0]} in
tag*)
tags=$(hc tag_status $monitor)
unset tags[${#tags[@]}-1]
;;
datetime)
datetime="${cmd[@]:1}"
;;
power_status)
power_status="${cmd[@]:1}"
;;
network_status)
network_status="${cmd[@]:1}"
;;
cpu_status)
cpu_status="${cmd[@]:1}"
;;
reload)
exit
;;
quit_panel)
exit
;;
esac
done
} 2> /dev/null | $executable -g ${panel_width}x${panel_height}+${x}+${y} -f $font -u $line_height -B $bgcolor -F $selfgcolor
ps
输出:
jakob@jw-laptop:~% ps faux | grep panel.sh
jakob 26906 0.0 0.0 12908 2324 pts/1 S+ 02:34 0:00 \_ grep --color panel.sh
jakob 26616 0.0 0.0 15780 3220 ? S 02:34 0:00 /usr/bin/bash /home/jakob/.config/herbstluftwm/panel.sh 0
jakob 26619 0.0 0.0 15780 1880 ? S 02:34 0:00 \_ /usr/bin/bash /home/jakob/.config/herbstluftwm/panel.sh 0
jakob 26622 0.0 0.0 15780 1624 ? S 02:34 0:00 | \_ /usr/bin/bash /home/jakob/.config/herbstluftwm/panel.sh 0
jakob 26625 0.0 0.0 15780 1752 ? S 02:34 0:00 | | \_ /usr/bin/bash /home/jakob/.config/herbstluftwm/panel.sh 0
jakob 26627 0.0 0.0 15780 1752 ? S 02:34 0:00 | | \_ /usr/bin/bash /home/jakob/.config/herbstluftwm/panel.sh 0
jakob 26624 0.0 0.0 15780 1628 ? S 02:34 0:00 | \_ /usr/bin/bash /home/jakob/.config/herbstluftwm/panel.sh 0
jakob 26633 0.0 0.0 15912 2496 ? S 02:34 0:00 | | \_ /usr/bin/bash /home/jakob/.config/herbstluftwm/panel.sh 0
jakob 26634 0.0 0.0 15780 480 ? S 02:34 0:00 | | \_ /usr/bin/bash /home/jakob/.config/herbstluftwm/panel.sh 0
jakob 26626 0.0 0.0 15780 1628 ? S 02:34 0:00 | \_ /usr/bin/bash /home/jakob/.config/herbstluftwm/panel.sh 0
jakob 26631 0.0 0.0 15912 2560 ? S 02:34 0:00 | | \_ /usr/bin/bash /home/jakob/.config/herbstluftwm/panel.sh 0
jakob 26632 0.0 0.0 15780 480 ? S 02:34 0:00 | | \_ /usr/bin/bash /home/jakob/.config/herbstluftwm/panel.sh 0
jakob 26628 0.0 0.0 15780 1624 ? S 02:34 0:00 | \_ /usr/bin/bash /home/jakob/.config/herbstluftwm/panel.sh 0
jakob 26637 0.0 0.0 15784 2556 ? S 02:34 0:00 | | \_ /usr/bin/bash /home/jakob/.config/herbstluftwm/panel.sh 0
jakob 26638 0.0 0.0 15780 476 ? S 02:34 0:00 | | \_ /usr/bin/bash /home/jakob/.config/herbstluftwm/panel.sh 0
jakob 26620 0.0 0.0 15912 2556 ? S 02:34 0:00 \_ /usr/bin/bash /home/jakob/.config/herbstluftwm/panel.sh 0
jakob@jw-laptop:~%
当我只有四个地方进行守护进程时,为什么有这么多进程?如果这个脚本使用了太多资源,我想修复它。
答案1
发生这种情况是因为您正在到处启动子 shell :-)
您正在使用的语法(在您所做的地方{ some_stuff } 2>/dev/null | other_stuff
)会为大括号之间的每一位代码创建一个子shell。这可以通过以下脚本相当容易地演示:
#!/bin/bash
{ sleep 1; } | { sleep 2; } | { sleep 3; } & ps axf
这会产生以下输出:
phemmer 26014 19 0 0.0 0.0 S+ 00:00 \_ bash /tmp/test.sh
phemmer 26015 19 0 0.0 0.0 S+ 00:00 \_ bash /tmp/test.sh
phemmer 26018 19 0 0.0 0.0 S+ 00:00 | \_ sleep 1
phemmer 26016 19 0 0.0 0.0 S+ 00:00 \_ bash /tmp/test.sh
phemmer 26020 19 0 0.0 0.0 S+ 00:00 | \_ sleep 2
phemmer 26017 19 0 0.0 0.0 S+ 00:00 \_ bash /tmp/test.sh
phemmer 26021 19 0 0.0 0.0 S+ 00:00 | \_ sleep 3
phemmer 26019 19 0 0.0 0.0 R+ 00:00 \_ ps axf
原因是管道中的所有命令必须同时运行。所以shell必须分叉。
这并不是一个巨大的资源浪费,因为 Linux 在分叉时使用写时复制内存分配。这意味着当进程分叉时,它的内存使用量不会增加一倍。两个进程将使用相同的内存,直到其中一个进程更改该内存为止。一旦发生更改,就会复制特定的内存页面。
唯一的解决方案是不在同一管道中执行脚本的多个部分。如何实现这一目标完全取决于您。
一种选择可能是exec
在子 shell 中使用最后一个命令。这样,正在运行的命令就会接管 shell 的 PID。