Linux script с отключением netcat после x часов

У меня есть сценарии:

#!/bin/bash

netcat -lk -p 12345 | while read line
do
    match=$(echo $line | grep -c 'Keep-Alive')
    if [ $match -eq 1 ]; then
        [start a command]
    fi
done

и

#!/bin/bash

netcat -lk -p 12346 | while read line
do
    match=$(echo $line | grep -c 'Keep-Alive')
    if [ $match -eq 1 ]; then
        [start a command]
    fi
done

Я поставил два сценария в '/etc/init.d/'

Когда я перезагружаю свою Linux-машину (RasbPi), оба скрипта работают нормально.

Я пробовал их как 20 раз, и они продолжают нормально работать.

Но примерно через 12 часов вся система перестает работать. Я включил некоторый loggin, но кажется, что скрипты больше не реагируют. Но когда я:

ps aux

Я вижу, что скрипты все еще запущены:

root      1686  0.0  0.2   2740  1184 ?        S    Aug12   0:00 /bin/bash /etc/init.d/script1.sh start
root      1689  0.0  0.1   2268   512 ?        S    Aug12   0:00 netcat -lk 12345
root      1690  0.0  0.1   2744   784 ?        S    Aug12   0:00 /bin/bash /etc/init.d/script1.sh start
root      1691  0.0  0.2   2740  1184 ?        S    Aug12   0:00 /bin/bash /etc/init.d/script2.sh start
root      1694  0.0  0.1   2268   512 ?        S    Aug12   0:00 netcat -lk 12346
root      1695  0.0  0.1   2744   784 ?        S    Aug12   0:00 /bin/bash /etc/init.d/script2.sh start

После перезагрузки они снова начинают работать... Но это грех, периодически перезагружая Linux-машину...

Я вставил некоторый loggin, вот результат;

Listening on [0.0.0.0] (family 0, port 12345)
[2013-08-14 11:55:00] Starting loop.
[2013-08-14 11:55:00] Starting netcat.
netcat: Address already in use
[2013-08-14 11:55:00] Netcat has stopped or crashed.
[2013-08-14 11:49:52] Starting loop.
[2013-08-14 11:49:52] Starting netcat.
Listening on [0.0.0.0] (family 0, port 12345)
Connection from [16.8.94.19] port 12345 [tcp/*] accepted (family 2, sport 6333)
Connection closed, listening again.
Connection from [16.8.94.19] port 12345 [tcp/*] accepted (family 2, sport 6334)
[2013-08-14 12:40:02] Starting loop.
[2013-08-14 12:40:02] Starting netcat.
netcat: Address already in use
[2013-08-14 12:40:02] Netcat has stopped or crashed.
[2013-08-14 12:17:16] Starting loop.
[2013-08-14 12:17:16] Starting netcat.
Listening on [0.0.0.0] (family 0, port 12345)
Connection from [16.8.94.19] port 12345 [tcp/*] accepted (family 2, sport 6387)
Connection closed, listening again.
Connection from [16.8.94.19] port 12345 [tcp/*] accepted (family 2, sport 6388)
[2013-08-14 13:10:08] Starting loop.
[2013-08-14 13:10:08] Starting netcat.
netcat: Address already in use
[2013-08-14 13:10:08] Netcat has stopped or crashed.
[2013-08-14 12:17:16] Starting loop.
[2013-08-14 12:17:16] Starting netcat.
Listening on [0.0.0.0] (family 0, port 12345)
Connection from [16.8.94.19] port 12345 [tcp/*] accepted (family 2, sport 6167)
Connection closed, listening again.
Connection from [16.8.94.19] port 12345 [tcp/*] accepted (family 2, sport 6168)

Спасибо

Ответ 1

О цикле это может выглядеть так.

#!/bin/bash

for (( ;; ))
do
    netcat -lk -p 12345 | while read line
    do
        match=$(echo "$line" | grep -c 'Keep-Alive')
        if [ "$match" -eq 1 ]; then
            [start a command]
        fi
    done
    sleep 4s
done

с добавленными двойными кавычками, чтобы сделать его более безопасным.

И вы можете попробовать захватить ошибки и добавить некоторые записи в этом формате:

#!/bin/bash

{
    echo "[$(date "+%F %T")] Starting loop."

    for (( ;; ))
    do
        echo "[$(date "+%F %T")] Starting netcat."

        netcat -lk -p 12345 | while read line
        do
            match=$(echo "$line" | grep -c 'Keep-Alive')
            if [ "$match" -eq 1 ]; then
                [start a command]
            fi
        done

        echo "[$(date "+%F %T")] Netcat has stopped or crashed."

        sleep 4s
    done
} >> "/var/log/something.log" 2>&1

Ваша команда чтения также может быть лучше в этом формате, так как она будет читать строки немодифицированные:

... | while IFS= read -r line

Некоторые могут также предложить использовать замену процессов, но я не рекомендую это на этот раз, так как с помощью метода | while ... цикл while мог бы работать на подоболочке и поддерживать внешний цикл for на всякий случай сбой. Кроме того, на самом деле нет переменной из цикла while, которая будет необходима вне нее.

Теперь у меня есть идея, что проблема может быть связана с входом и как блок while read line; do ...; done обрабатывает его , а не сам netcat. Ваши переменные, которые не правильно цитируются вокруг "", могут быть одним из них, или, возможно, фактической причиной, почему ваш netcat сбой.

Ответ 2

Если ни одна из ваших команд, включая netcat, не считывает входные данные из stdin, вы можете полностью запустить ее независимо от терминала. Иногда фоновый процесс, который все еще зависит от терминалов, приостанавливает (S), когда они пытаются прочитать ввод из него на фоне. Фактически, поскольку вы используете демона, вы должны убедиться, что ни одна из ваших команд не считывает ввод с него (терминал).

#!/bin/bash

set +o monitor # Make sure job control is disabled.

(
    : # Make sure the shell runs a subshell.
    exec netcat -lk -p 12345 | while read line  ## Use exec to overwrite the subshell.
    do
        match=$(echo $line | grep -c 'Keep-Alive')
        if [ $match -eq 1 ]; then
            [start a command]
        fi
    done
) <&- >&- 2>&- </dev/null &>/dev/null &

TASKPID=$!
sleep 1s ## Let the task initialize a bit before we disown it.
disown "$TASKPID"

И я думаю, мы могли бы попробовать снова выполнить запись:

set +o monitor

(
    echo "[$(date "+%F %T")] Starting loop with PID $BASHPID."

    for (( ;; ))
    do
        echo "[$(date "+%F %T")] Starting netcat."

        netcat -vv -lk -p 12345 | while read line
        do
            match=$(echo "$line" | grep -c 'Keep-Alive')
            if [ "$match" -eq 1 ]; then
                [start a command]
            fi
        done

        echo "[$(date "+%F %T")] Netcat has stopped or crashed."

        sleep 4s
    done
) <&- >&- 2>&- </dev/null >> "/var/log/something.log" 2>&1 &

TASKPID=$!
sleep 1s
disown "$TASKPID"

Ответ 3

Вы упомянули "примерно через 12 часов, вся система перестает работать". Вероятно, скрипты выполняют все, что у вас есть, в [start a command] и раздувают память. Вы уверены, что [start a command] не очень часто вызывает много процессов и освобождает память?

Ответ 4

Я часто испытывал странное поведение с nc или netcat. Вы должны взглянуть на ncat почти такой же инструмент, но он ведет себя одинаково на всех платформах (nc и netcat ведут себя по-разному в зависимости от дистрибутива, linux, BSD, Mac).

Ответ 5

Периодически netcat будет печатать, а не строку, а блок двоичных данных. В результате, как правило, сбой встроенного чтения.

Я думаю, вы используете эту программу для проверки того, что удаленный хост все еще подключен к портам 12345 и 12346 и не перезагружен.

Мое решение для вас - передать вывод netcat в sed, а затем передать эту (значительно уменьшенную) строку в read builtin...

#!/bin/bash

{
    echo "[$(date "+%F %T")] Starting loop."

    for (( ;; ))
    do
        echo "[$(date "+%F %T")] Starting netcat."

        netcat -lk -p 12345 | sed 's/.*Keep-Alive.*/Keep-Alive/g' | \
        \
        while read line
        do
            match=$(echo "$line" | grep -c 'Keep-Alive')
            if [ "$match" -eq 1 ]; then
                [start a command]
            fi
        done

        echo "[$(date "+%F %T")] Netcat has stopped or crashed."

        sleep 4s
    done
} >> "/var/log/something.log" 2>&1

Кроме того, вам нужно будет просмотреть некоторые из других программ запуска в /etc/init.d, чтобы убедиться, что они совместимы с любой версией rc, используемой системой, однако было бы гораздо проще вызвать ваш скрипт2.sh из копии некоторого простого файла в init.d. Поскольку это сценарий2, это запуск script, но не соответствует используемому пакету init.

Это звучит более сложно, я имею в виду... Позвольте мне объяснить лучше:

/etc/init.d/syslogd        ## a standard init script that calls syslogd
/etc/init.d/start-monitor   ## a copy of a standard init script that calls script2.sh

В качестве дополнительной заметки, я думаю, вы могли бы привязать netcat к определенному IP-адресу, который вы контролируете, вместо привязки его ко всему адресу 0.0.0.0

Ответ 6

вы не можете использовать опцию -p в случае, если вы будете ждать входящего запроса на соединение. (см. справочную страницу nc) Имя хоста и порт - последние два аргумента командной строки.

Может быть, он подключается к собственному порту, и через несколько часов отсутствует какой-то ресурс?