#!/bin/bash

# Skrypt killall wysyłający określony sygnał do wszystkich procesów, których
# nazwy są zgodne z podanym wzorcem.

# Domyślnie skrypt przerywa wyłącznie procesy, których właścicielem jest
# użytkownik uruchamiający skrypt, chyba że jest to użytkownik root.
# Użyj argumentu -s SYGNAŁ, aby określić sygnał wysyłany do procesu,
# -u UŻYTKOWNIK do określenia właściciela, -t TTY do określenia
# terminala lub argumentu -n w celu wyświetlenia jedynie planowanych
# poleceń bez ich wykonywania.

signal="-INT"      # Domyślnym sygnałem jest przerwanie.
user=""   tty=""   donothing=0

while getopts "s:u:t:n" opt; do
  case "$opt" in
    # Zwróć uwagę na zastosowaną sztuczkę: polecenie kill wymaga 
    # podania argumentu -SYGNAŁ  Ponieważ argumentem skryptu jest
    # SYGNAŁ, należy poprzedzić go znakiem '-'.
    s ) signal="-$OPTARG";              ;;
    u ) if [ ! -z "$tty" ] ; then
          # Błąd logiczny, nie można określić jednocześnie użytkownika i terminala.
          echo "$0: Błąd: argumenty -u i -t wykluczają się wzajemnie." >&2
          exit 1
        fi
        user=$OPTARG;                  ;;
    t ) if [ ! -z "$user" ] ; then
          echo "$0: Błąd: argumenty -u i -t wykluczają się wzajemnie." >&2
          exit 1
        fi
        tty=$2;                        ;;
    n ) donothing=1;                    ;;
    ? ) echo "Użycie: $0 [-s sygnał] [-u użytkownik|-t terminal] [-n] wzorzec" >&2
        exit 1
  esac
done

# Koniec przetwarzania argumentów za pomocą polecenia getopts.
shift $(( $OPTIND - 1 ))

# Kod wykonywany, gdy użytkownik nie poda żadnych argumentów
# (ten sam kod jest wykonywany wcześniej w wyniku użycia argumentu -?).
if [ $# [21~-eq 0 ] ; then
  echo "Użycie: $0 [-s sygnał] [-u użytkownik|-t terminal] [-n] wzorzec" >&2
  exit 1
fi

# Teraz tworzona jest lista identyfikatorów procesów zgodnych z podanym wzorcem
# i urządzeniem, dla podanego lub bieżącego użytkownika.

if [ ! -z "$tty" ] ; then
  pids=$(ps cu -t $tty | awk "/ $1$/ { print \$2 }")
elif [ ! -z "$user" ] ; then
  pids=$(ps cu -U $user | awk "/ $1$/ { print \$2 }")
else
  pids=$(ps cu -U ${USER:-LOGNAME} | awk "/ $1$/ { print \$2 }")
fi

# Brak pasujących procesów? Żaden problem!
if [ -z "$pids" ] ; then
  echo "$0: brak procesów zgodnych ze wzorcem $1" >&2; exit 1
fi

for pid in $pids
do
  # Wysłanie sygnału $signal do procesu o identyfikatorze $pid. Polecenie kill
  # może wyświetlić komunikaty, że proces nie zakończył działania, użytkownik
  # nie ma uprawnień itp. To normalne. Tak czy owak, skrypt wykonał
  # swoje zadanie.
  if [ $donothing -eq 1 ] ; then
    echo "kill $signal $pid"   # Argument -n oznacza:
                               # "wyświetl polecenie, ale nie wykonuj go".
  else
    kill $signal $pid
  fi
done

exit 0
