Linuxでグラフバー用のbashスクリプトを作成しましたが、スクリプトがあまりにも多くのプロセスを生成しているようです。
スクリプト:
#!/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:~%
デーモン化できる場所が4つしかないのに、なぜプロセスがそんなに多いのですか?このスクリプトがあまりにも多くのリソースを使用している場合は、それを修正したいと思います。
ベストアンサー1
これはどこでもサブシェルを起動するために発生します:-)
使用中の構文(使用中の場所{ some_stuff } 2>/dev/null | other_stuff
)は、中かっこ間のすべてのコードビットのサブシェルを生成します。これは、次のスクリプトを使用してかなり簡単に説明できます。
#!/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
その理由は、パイプライン内のすべてのコマンドを同時に実行する必要があるためです。したがって、シェルをフォークする必要があります。
Linuxはフォーク時に書き込み時にコピーメモリ割り当てを使用するため、これは大きなリソースの無駄ではありません。これは、プロセスがフォークされたときにメモリ使用量が2倍にならないことを意味します。両方のプロセスのいずれかがそのメモリを変更するまで、両方のプロセスは同じメモリを使用します。変更が発生すると、特定のメモリページがコピーされます。
唯一の解決策は、同じパイプラインでスクリプトの複数の部分を実行しないことです。これを達成する方法は完全にあなた次第です。 1つのオプションは、サブシェルで最後のコマンドを使用する
ことです。exec
このように実行されているコマンドは、シェルのPIDを引き継ぎます。