Bash 스크립트 및 프로세스

Bash 스크립트 및 프로세스

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는 포크할 때 쓰기 시 복사 메모리 할당을 사용하므로 이는 큰 리소스 낭비가 아닙니다. 이는 프로세스가 포크될 때 메모리 사용량이 두 배가 되지 않음을 의미합니다. 두 프로세스 중 하나가 해당 메모리를 변경할 때까지 두 프로세스 모두 동일한 메모리를 사용합니다. 변경이 발생하면 특정 메모리 페이지가 복사됩니다.

유일한 해결책은 동일한 파이프라인에서 스크립트의 여러 부분을 실행하지 않는 것입니다. 이를 달성하는 방법은 전적으로 귀하에게 달려 있습니다. 한 가지 옵션은 서브셸에서 마지막 명령을 사용하는
것입니다 . exec이러한 방식으로 실행 중인 명령은 셸의 PID를 인수합니다.

관련 정보