Fórum Root.cz

Hlavní témata => Software => Téma založeno: tuxmartin 02. 08. 2016, 23:09:01

Název: Bash: info mail o dokončení příkazu
Přispěvatel: tuxmartin 02. 08. 2016, 23:09:01
Ahoj,
obcas provadim prikazy, ktere trvaji hodne casu. Radove hodiny, nekdy i vice. Poustim je ve screenu.
Rad bych nejak jednoduse dostal oznameni, ze byl prikaz ukoncen a zda uspesne, nebo neuspesne. Hlavne by melo byt jednoduche pouziti.
Protoze prikazu je vice, potrebuju znat i presny string prikazu vcetne parametru.

Co potrebuju:
Kód: [Vybrat]
ps -aux | grep "rsyslogd" ; necoCoPosleNotifikace
Pokud pouziju !:0 !:*, castecne to funguje:

Kód: [Vybrat]
$ ps -aux | grep "rsyslogd"
syslog    1663  0.0  0.0 255836  1648 ?        Ssl  čec27   0:00 rsyslogd
martin    6232  0.0  0.0  11880   936 pts/4    S+   22:54   0:00 grep --color=auto rsyslogd
$ echo "Prikaz: '!:0 !:*' byl ukoncen: $?"                 # ******************
$ echo "Prikaz: 'ps -aux | grep "rsyslogd"' byl ukoncen: $?"
Prikaz: 'ps -aux | grep rsyslogd' byl ukoncen: 0
$

$ ps -aux | grep "rsyslogd" ; echo "Prikaz: '!:0 !:*' byl ukoncen: $?"
$ ps -aux | grep "rsyslogd" ; echo "Prikaz: 'echo "Prikaz: 'ps -aux | grep "rsyslogd"' byl ukoncen: $?"' byl ukoncen: $?"   # ***************
syslog    1663  0.0  0.0 255836  1648 ?        Ssl  čec27   0:00 rsyslogd
martin    6239  0.0  0.0  11880   936 pts/4    S+   22:55   0:00 grep --color=auto rsyslogd
Prikaz: 'echo Prikaz: ps -aux | grep "rsyslogd" byl ukoncen: 0' byl ukoncen: 0
$

Kdyz zadam prikaz oznaceny hvezdickami a potvrdim enter, tak misto vypisu dostanu predvyplneny prikaz na radku pod nim a musim znova zmacknout enter.

Pokud si zkusim poslat mail, vubec se prikaz nevyhodnoti:

Kód: [Vybrat]
#!/bin/bash
# /tmp/notify.sh
{
echo "Prikaz: '!:0 !:*' byl ukoncen: $?"
} | mail -s "PRIKAZ DOKONCEN" mujmail@example.net

Kód: [Vybrat]
ps -aux | grep "rsyslogd" ; /tmp/notify.sh
A v mailu je:
Kód: [Vybrat]
Prikaz: '!:0 !:*' byl ukoncen: 0
Alias se mi nedari vubec zadefinovat:
Kód: [Vybrat]
alias notify="echo \"Prikaz: '!:0 !:*' byl ukoncen: $?\" | mail -s 'PRIKAZ DOKONCEN' mujmail@example.net"

ps -aux | grep "rsyslogd" ; notify

Odesilani idealne na mail, nebo pres curl poslat android push notifikaci. To je jedno.

Znate nekdo reseni?
Název: Re:Bash: info mail o dokonceni prikazu
Přispěvatel: e3k 02. 08. 2016, 23:16:57
echo "zbehlo to. chod na pivo!" | sendmail admin@bitfactory.cz
Název: Re:Bash: info mail o dokonceni prikazu
Přispěvatel: Kit 02. 08. 2016, 23:19:23
Problém bude v tom, že pokud použiješ kolonu, je vyhodnocena v subshellu, který nemusí zdědit všechny proměnné od rodičovského procesu. Zkus tohle:
Kód: [Vybrat]
export hotovo="Prikaz: '!:0 !:*' byl ukoncen: $?"
echo "$hotovo" | mail -s 'PRIKAZ DOKONCEN' mujmail@example.net"
Název: Re:Bash: info mail o dokonceni prikazu
Přispěvatel: tuxmartin 02. 08. 2016, 23:26:06
echo "zbehlo to. chod na pivo!" | sendmail admin@bitfactory.cz

Ja ale chci znat cely string prikazu:

ps -aux | grep "rsyslogd"
echo "NECO" | sendmail admin@bitfactory.cz

a v mailu ocekavam

Kód: [Vybrat]
Predmet:
  DOKONCENO

Text mailu:
  ps -aux | grep "rsyslogd"
  0

0=uspech ($?)

A mit to automatizovane. Proste za libovolnym prikazem zavolat "notify".


Kód: [Vybrat]
export hotovo="Prikaz: '!:0 !:*' byl ukoncen: $?"
echo "$hotovo" | mail -s 'PRIKAZ DOKONCEN' mujmail@example.net"

Nefunguje :-(
Název: Re:Bash: info mail o dokončení příkazu
Přispěvatel: Kit 02. 08. 2016, 23:28:06
Ještě k tomu dodám, že kolonu nelze dát do aliasu, podobně jako sekvenci či cyklus. Můžeš ji však nadefinovat jako funkci shellu.
Název: Re:Bash: info mail o dokonceni prikazu
Přispěvatel: Kit 02. 08. 2016, 23:31:32
Kód: [Vybrat]
export hotovo="Prikaz: '!:0 !:*' byl ukoncen: $?"
echo "$hotovo" | mail -s 'PRIKAZ DOKONCEN' mujmail@example.net"

Nefunguje :-(

Nejspíš bude nutné odstranit tu zbytečnou uvozovku na konci druhého řádku, kterou jsem omylem zkopíroval také.

Jinak pokud to "Nefunguje", tak to máš asi rozbité.
Název: Re:Bash: info mail o dokonceni prikazu
Přispěvatel: tuxmartin 03. 08. 2016, 00:26:50
Jinak pokud to "Nefunguje", tak to máš asi rozbité.

Uvozovku jsem odmazal. Ale nevim, jak jednoduse prikaz pouzit.

Muzes mi prosim poslat ukazku napr. pro vypis "ls -lh /"?
Název: Re:Bash: info mail o dokonceni prikazu
Přispěvatel: Tuxik 03. 08. 2016, 06:37:59
Jinak pokud to "Nefunguje", tak to máš asi rozbité.

Uvozovku jsem odmazal. Ale nevim, jak jednoduse prikaz pouzit.

Muzes mi prosim poslat ukazku napr. pro vypis "ls -lh /"?

Co třeba
Kód: [Vybrat]
ls -lh / | mail -s "Tady mas svoje LS" mail@domena.cz
ale spíš bych hádal, že nemáš nastavený žádný mailer, který by to uměl někam poslat.
Název: Re:Bash: info mail o dokončení příkazu
Přispěvatel: Tuxik 03. 08. 2016, 08:35:07
Tak jsem na to koukal pořádně, co vlastně chceš a největší problém je s tím exit codem, kterej přej pajpu neprotlačíš. Doporučoval bych vytvořit soubor s funkcí, například notify.sh a umístit ho třeba do /usr/local/bin

Kód: [Vybrat]
mail_notify() {
    mail_body="Vystup:\n"
    mail_body+=$($@)
    mail_body+="\n\nExit status: $?"
    IFS=''
    echo -e $mail_body | mail -s "Vysledek $0" user@domena.tld
}

ve svým skriptu potom použiješ
Kód: [Vybrat]
source notify.sha co budeš chtít takto odchytit, tak spustíš použitím mail_notify před příkaz, například
Kód: [Vybrat]
mail_notify ls -lh /Do mailu ti přijde
Kód: [Vybrat]
Vystup:
total 85K
drwxrwxr-x   2 root root 4.0K Jul 19 07:57 bin
drwxr-xr-x   4 root root 1.0K Jul 19 08:01 boot
drwxr-xr-x  18 root root 3.1K Jul 19 08:01 dev
.....

Exit status: 0

Není to asi úplně neprůstřelný řešení, ale je to jednoduchý na zadání. Blbý je, že to jako parametr požere všechno co je za voláním funkce, takže už se třeba nedá předat jiná mailová adresa - použije se ta, co je natvrdo ve skriptu. To by se dalo ještě upravit nějakým voláním
Kód: [Vybrat]
USE_MAIL=mail@neco.ru mail_notify ls -lh /a patřičnou změnou řádku v notify.sh na
Kód: [Vybrat]
echo -e $mail_body | mail -s "Vysledek $0" $USE_MAILnebo ještě lépe testovat USE_MAIL a pokud není nastavená, použít nějakou výchozí adresu, ale to už si pohraj podle toho, co budeš potřebovat.
Název: Re:Bash: info mail o dokonceni prikazu
Přispěvatel: tuxmartin 03. 08. 2016, 16:19:39
Kód: [Vybrat]
ls -lh / | mail -s "Tady mas svoje LS" mail@domena.czale spíš bych hádal, že nemáš nastavený žádný mailer, který by to uměl někam poslat.

Posilani mailu funguje.

Ja ale nechci mit v mailu vystup prikazu ls, ale text "ls -lh /".



Tak jsem na to koukal pořádně, co vlastně chceš a největší problém je s tím exit codem, kterej přej pajpu neprotlačíš. Doporučoval bych vytvořit soubor s funkcí, například notify.sh a umístit ho třeba do /usr/local/bin

Soubor se skriptem neni problem. Pocital jsem s tim.

Problem je, ze krome vystupu prikazu (take se hodi) potrebuju hlavne prikaz samotny.
Protoze kdyz spustim 10x screen a v kazdem neco jineho, musim identifikovat, ktery je ktery.

Umel bys to nejak upravit?
Název: Re:Bash: info mail o dokončení příkazu
Přispěvatel: Tuxik 03. 08. 2016, 17:52:18
Tak třeba takhle?

Kód: [Vybrat]
mail_notify() {
    mail_body="Prikaz: $@\n\n"
    mail_body+="Vystup:\n"
    mail_body+=$($@)
    mail_body+="\n\nExit status: $?"
    IFS=''
    echo -e $mail_body | mail -s "Hotovo: $(echo -e $@)" mail@domena.xxx
}

Budeš mít příkaz v předmětu jako "Hotovo: ls -lh /" a bude to uvevdeno i na začátku emailu.
Název: Re:Bash: info mail o dokončení příkazu
Přispěvatel: Tuxik 03. 08. 2016, 21:56:54
A že mám dobrou náladu tak:
Kód: [Vybrat]
mail_notify() {
    DEFAULT_MAIL=user@domain.info
    VERBOSE=NO
    IFS=''
    params_count=$#;
    params_array=( "$@" )
    param=0
    while [ $param -lt $params_count ]; do
        if [ ${params_array[$param]} = "-v" ]; then
            VERBOSE=YES
            let param++
            continue
        fi
        if [ ${params_array[$param]} = "-n" ]; then
            VERBOSE=NO
            let param++
            continue
        fi
        if [ ${params_array[$param]} = "-a" ]; then
            let param++
            DEFAULT_MAIL=${params_array[$param]}
            let param++
            continue
        fi
        while [ $param -lt $params_count ]; do
            command+=${params_array[$param]}" "
            let param++
        done
        break
    done
    mail_body="Prikaz: $command\n"
    if [ $VERBOSE = "YES" ]; then
        mail_body+="\nVystup:\n"
        mail_body+=$(eval $command 2>&1)"\n\n"
    else
        eval $command 2>&1
    fi
    mail_body+="Exit status: $?"
    echo -e $mail_body | mail -s "Hotovo: $(echo -e $command)" $DEFAULT_MAIL
}

nahoře je nastavený VERBOSE a DEFAULT_MAIL
verbose se dá přehodit parametry -v jako verbose a -n jako ne verbose, verbose do mailu přidává výstup programu a ne verbose ho tam nedá
mail se dá změnit parametrem -a jako adresa a následně adresou.

takže například volání
Kód: [Vybrat]
mail_notify -a jouda@seznam.cz -v ls -lh /pošle info o příkazu ls -lh / na adresu jouda@seznam.cz včetně výstupu

modifikující parametry musí být vždy na začátku, pokud to narazí na první neznámý parametr, je od tohoto místa až do konce řádku považován za příkaz ke spuštění.

Nemá to žádný kontroly, je třeba buď dávat pozor, nebo si je dopsat.

A ještě jeden detail - ve verbose modu nevypisuje výstup do konzole, ale posílá je jen na mail, v ne verbose modu to vypisuje do konzole.
Název: Re:Bash: info mail o dokončení příkazu
Přispěvatel: tuxmartin 03. 08. 2016, 23:08:19
A že mám dobrou náladu tak:

Diky! To je temer ono.
Uz se posle do mailu nazev prikazu.

Jde jeste nejak poslat i to, co je za rourou?

Kód: [Vybrat]
martin@martin:/tmp$ mail_notify ps -aux | grep syslog
syslog    1663  0.0  0.0 255836  1728 ?        Ssl  čec27   0:00 rsyslogd
martin    3669  0.0  0.0 370332  6512 ?        Sl   čec27   6:22 /usr/bin/pulseaudio --start --log-target=syslog
martin   23852  0.0  0.0  11880   932 pts/9    S+   23:05   0:00 grep --color=auto syslog
martin@martin:/tmp$

Takhle prijde mail "Hotovo: ps -aux" misto "Hotovo: ps -aux | grep syslog".
Název: Re:Bash: info mail o dokonceni prikazu
Přispěvatel: e3k 03. 08. 2016, 23:15:44
Kód: [Vybrat]
ls -lh / | mail -s "Tady mas svoje LS" mail@domena.czale spíš bych hádal, že nemáš nastavený žádný mailer, který by to uměl někam poslat.

Posilani mailu funguje.

Ja ale nechci mit v mailu vystup prikazu ls, ale text "ls -lh /".
chces toto?:
Kód: [Vybrat]
echo 'ls -lh /' | mail -s "Tady mas svoje LS" mail@domena.cz
Název: Re:Bash: info mail o dokončení příkazu
Přispěvatel: Ravise 04. 08. 2016, 00:09:47
Možná by pomohl příkaz history. Z něj se dá dostat "celá řádka" toho příkazu (vč. rour, && řetězení, oddělení středníkem a tak)

history | tail

 1987  ps -aux | grep syslog
 1988  history | tail
(kráceno)
Název: Re:Bash: info mail o dokončení příkazu
Přispěvatel: Tuxik 04. 08. 2016, 09:47:44
No ty mi dáváš teda... rouru musíš eskejpovat jako \| , případně dát celej příkaz do uvozovek, takže
Kód: [Vybrat]
mail_notify ps -aux \| grep syslognebo
Kód: [Vybrat]
mail_notify "ps -aux | grep syslog"nicméně s rourou to hodí exit status pouze posledního příkazu v rouře, takže celý předělat takto:
Kód: [Vybrat]
    DEFAULT_MAIL=mail@kdesi.cosi
    VERBOSE=NO
    IFS=''
    params_count=$#;
    params_array=( "$@" )
    param=0
    while [ $param -lt $params_count ]; do
        if [ ${params_array[$param]} = "-v" ]; then
            VERBOSE=YES
            let param++
            continue
        fi
        if [ ${params_array[$param]} = "-n" ]; then
            VERBOSE=NO
            let param++
            continue
        fi
        if [ ${params_array[$param]} = "-a" ]; then
            let param++
            DEFAULT_MAIL=${params_array[$param]}
            let param++
            continue
        fi
        while [ $param -lt $params_count ]; do
            command+=${params_array[$param]}" "
            let param++
        done
        break
    done
    mail_body="Prikaz: $command\n"
    origcommand=$command;
    if [ $VERBOSE = "YES" ]; then
        commandadd=" 2>&1; "
    else
        commandadd=" > /dev/null; "
    fi
    commandadd+='mypipe=(${PIPESTATUS[@]}); '
    commandadd+='echo -e "\nVysledky:"; '
    commandadd+='IFS="|"; '
    commandadd+='read -r -a parts <<< "$origcommand"; '
    commandadd+='for (( c=0; c<${#mypipe[@]}; c++)); do echo ${parts[$c]} : exit status ${mypipe[$c]} | sed -e "s/^[[:space:]]*//" | sed -e "
s/[[:space:]]*$//" ;done;'
    if [ $VERBOSE = "YES" ]; then
        mail_body+="\nVystup:\n"
    fi
    mail_body+=$(eval $command $commandadd)
    echo -e $mail_body | mail -s "Hotovo: $(echo -e $origcommand)" $DEFAULT_MAIL

a na konci mailu ti to vypíše exit statusy všech částí roury po jedné.
Název: Re:Bash: info mail o dokončení příkazu
Přispěvatel: tuxmartin 04. 08. 2016, 12:28:58
Uz to skoro mam.

Skript notify.sh:
Kód: [Vybrat]
#!/bin/bash

mail_notify() {
exit_status="$?"
cmd_output="$($@)"
hostname=`cat /etc/hostname`
        mail_body="Prikaz: \n"
        mail_body+="----------------------------------\n"
        mail_body+=`history | tail -n 1 | cut -c 8-`
mail_body+="\n----------------------------------\n\n\n"
mail_body+="Vystup:\n"
mail_body+="----------------------------------\n"
mail_body+=$cmd_output
        mail_body+="\n----------------------------------\n"
mail_body+="\n\nExit status: $exit_status"
IFS=''
echo $cmd_output
echo -e $mail_body | mail -s "PRIKAZ [$hostname]: $exit_status" mujmail@gmail.com
}

V bashrc mam:
Kód: [Vybrat]
source notify.sh
A ukazka pouziti:
Kód: [Vybrat]
$ mail_notify ls -lh / | grep "etc"
drwxr-xr-x 182 root root  12K srp  2 22:11 etc
$

Otazka zni: proc v mailu je vystup prikazu bez grepu (za rourou), ale na stdout se to vypise spravne? viz obrazek v priloze
Název: Re:Bash: info mail o dokončení příkazu
Přispěvatel: Tuxik 04. 08. 2016, 12:42:55
No to sem ti psal, musíš tu rouru escapovat, místo | napiš \| , jinak to provede pouze
Kód: [Vybrat]
mail_notify ls -lh /a až výstup toho prožene přes rouru a do
Kód: [Vybrat]
grep "etc"

Navíc i když to escapuješ, při použití roury bude exitcode pouze pro poslední příkaz v rouře, takže viz zdroják výše, kterej to pořeší a vypíše exitcode pro každou z částí zvlášť.