Bash 脚本和进程

Bash 脚本和进程

我创建了一个 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。

相关内容