Script e processos Bash

2

Eu criei um script bash para uso com uma barra gráfica no Linux, no entanto, o script parece gerar muitos processos.

O script:

#!/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 output:

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:~%

Por que tantos processos, quando há apenas quatro lugares onde eu daemonizei? Se este script estiver usando muitos recursos, eu gostaria de corrigi-lo.

    
por Patrick 08.07.2014 / 02:42

1 resposta

2

Isso está acontecendo porque você está lançando subshells por todo o lugar: -)

A sintaxe que você está usando, onde você faz { some_stuff } 2>/dev/null | other_stuff , cria um subshell para cada bit de código entre as chaves. Isso pode ser demonstrado facilmente com o seguinte script:

#!/bin/bash
{ sleep 1; } | { sleep 2; } | { sleep 3; } & ps axf

Que resulta na seguinte saída:

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

A razão para isso é porque todos os comandos em um pipeline devem ser executados ao mesmo tempo. Então a casca tem que bifurcar-se.

Este não é um grande desperdício de recursos, já que o Linux usa a alocação de memória copy-on-write ao forjar. O que significa que quando um processo se bifurca, o uso de memória não é duplicado. Ambos os processos usarão a mesma memória até que um dos processos altere essa memória. Depois de alterado, essa página de memória específica é copiada.

A única solução para isso é não executar várias partes do script no mesmo pipeline. Como você consegue isso depende inteiramente de você.
Uma opção pode ser usar um exec para o último comando no subshell. Desta forma, o comando que está sendo executado assume o PID do shell.

    
por 08.07.2014 / 07:35

Tags