User Tools

Site Tools


средства_программирования_shell

Table of Contents

Средства программирования shell

Проверка синтаксиса

# apt install shellcheck

$ shellcheck webd/webd

Переменные окружения

Объединение команд

Последовательность команд в строке

$ echo -n "Enter Name: "; read a; echo Hello $a

$ sleep 3; echo -e "\007"

Последовательности команд в текстовом файле

$ cat ex1.txt
echo -n "Enter Name: "
read p
echo Hello $p
$ sh ex1.txt

$ . ex1.txt

Последовательности команд в выполняемом файле

$ cat ex1.sh
#!/bin/sh
echo -n "Enter Name: "
read p
echo Hello "$p !!!"
$ chmod +x ex1.sh

$ ex1.sh

$ /home/userX/ex1.sh

$ ./ex1.sh

Последовательность команд в функции

$ mycd () {
> cd $1
> PS1="`pwd` $ "
> }

Примеры простых алгоритмов и вариантов использования

Целочисленный цикл (поиск хостов в подсети)

$ cat test_ping.sh
#!/bin/sh

#test -z $1 && exit 1
#[ "$1" ] || { echo Example: ./test_ping.sh 10.5.11; exit 1; }

i=1
while [ $i -lt 254 ]
do
  test $i = 50 && continue
  ping -c 1 -W 1 $1.$i > /dev/null 2>&1 && echo $1.$i || echo No $i
  i=$(($i + 1))
done
$ cat arp_ping.sh
#!/bin/sh

test $# -lt 1 && exit 1

i=1
while :
do
  ip=$1.$i

  ping -c 1 -W 1  $ip >/dev/null
  ip n | grep "$ip " | grep -q  ':..:..:' && echo $ip

  i=$(($i + 1))
  test $i -eq 254 && break
done

Цикл for - обработка множеств (массовое переименование файлов)

for i in *sample; do cp $i ${i%.sample}; done

Чтение полей из файла

$ cat readifs.sh
#!/bin/sh
IFS=:
while read a b c d e f g
do
  echo "$a $g"
done < /etc/passwd
#!/bin/sh
for i in `cut -d: -f1 /etc/passwd`
do
  echo user $i
done

Перехват сигналов

$ cat trap.sh
#!/bin/sh
trap "echo got signal 2; date" 2
while : ; do
	cat <<MENU
**********
* Exit ? *
*  Yes   *
*  No    *
**********
MENU
        echo -n "Enter your choose: "
        read a
        case $a in
        [Yy][eE][sS])
                echo "Success"
                exit 0
                ;;
        *)
                echo "Not Success"
                ;;
        esac
done

Использование файловых дескрипторов

Параллельное чтение двух файлов

$ cat report.sh
#!/bin/sh

exec 3<file1.txt
exec 4<file2.txt

exec 0<&3
while read a
do
        exec 0<&4
        read b
        exec 0<&3
        echo $a $b
done

Передача сообщений в syslog

$ cat log_gen.sh
while :
do
  logger -t cisco -p local0.info "Message 1"
  logger -t cisco -p local0.info "Message 2"
done
$ sh cisco_log_gen.sh

Примеры использования скриптов sh в системах загрузки

Система загрузки rc.local (устаревший способ)

# cat /etc/rc
#!/bin/sh

/usr/sbin/sshd

Система загрузки SysV (Linux)

Запуск сервисов

# cat /etc/init.d/ssh 
#!/bin/sh

if [ "$1" = start ]
then
        echo Starting sshd...
        /usr/sbin/sshd
elif [ "$1" = stop ]
then
        echo Stopping sshd...
        kill -TERM `cat /var/run/sshd.pid`
        while [ -e /var/run/sshd.pid ]
        do 
                sleep 1
        done
else 
        echo Usage:
        echo "$0 start|stop"
fi
# cd /etc/init.d
# ln -s ../init.d/ssh /etc/rc2.d/S10ssh
# ln -s ../init.d/ssh /etc/rc0.d/K15ssh 
# ln -s ../init.d/ssh /etc/rc6.d/K25ssh

# cat /etc/init.d/rc
#!/bin/sh

runlevel=$1

for s in /etc/rc${runlevel}.d/[SK]*; do
  if test $s != ${s##/etc/rc${runlevel}.d/S??}  
  then 
    $s start
  else
    $s stop
  fi
done
# chmod +x /etc/init.d/rc

# /etc/init.d/rc 2

# /etc/init.d/rc 0

Система загрузки rc.NG (NetBSD, FreeBSD)

Запуск сервисов

$ cat /etc/rc.d/sshd
#!/bin/sh

. /etc/defaults/rc.conf
. /etc/rc.conf

case "$sshd_enable" in
[Yy][Ee][Ss])
        if [ "$1" = start ]
        then
                echo Starting sshd...
                /usr/sbin/sshd
        elif [ "$1" = stop ]
        then
                echo Stopping sshd...
                kill -s TERM `cat /var/run/sshd.pid`
                while [ -e /var/run/sshd.pid ]
                do 
                        sleep 1
                done
        else 
                echo Usage:
                echo '/etc/rc.d/sshd start|stop'
        fi
        ;;
esac
$ cat /etc/rc.conf
...
sshd_enable=YES
...
$ cat /etc/rc
#!/bin/sh

for i in /etc/rc.d/*
do
        $i $1
done

Настройка сетевых маршрутов

$ cat /etc/rc.conf
static_routes="wg1 wg2"
route_wg1="10.10.10.0/24 10.10.106.100"
route_wg2="10.10.20.0/24 10.10.106.100"
$ cat /etc/rc.d/routing
#!/bin/sh
. /etc/rc.conf
for i in ${static_routes} 
do
    eval route_arg=\$route_${i}
    route add $route_arg
done

Настройка сетевых интерфейсов

$ cat /etc/rc.conf
...
ifconfig_fxp0="inet 10.5.2.17/24"
ifconfig_fxp0_alias0="inet 10.5.2.18/32"
ifconfig_fxp0_alias1="inet 10.5.2.19/32"
ifconfig_fxp0_alias2="inet 192.168.15.1/24"
...
$ cat /etc/rc.d/netif
#!/bin/sh

. /etc/rc.conf

for intf in `ifconfig | grep mtu | cut -d: -f1`
do
        eval args=\$ifconfig_$intf
        if [ -n "$args" ]
        then
                ifconfig $intf $args
                alias=0
                while : ; do
                        eval ifconfig_args=\$ifconfig_${intf}_alias${alias}
                        if [ -n "${ifconfig_args}" ]
                        then
                                ifconfig $intf ${ifconfig_args} alias
                                alias=$((${alias} + 1))
                        else
                                break
                        fi
                done
        fi
done

Дополнительные материалы

Расширения BASH

$ echo a{1..5}b

$ echo a{1,3,5}b

CGI на shell

Web сервер на shell

# cat /usr/local/sbin/webd
#!/bin/bash
base=/var/www
#log=/var/log/webd.log

read request
##echo "$request" >> $log       # for educational demonstration

filename="${request#GET }"
filename="${filename% HTTP/*}"

test $filename = "/" && filename="/index.html"

filename="$base$filename"

while :
do
  read -r header
##  echo "$header" >> $log       # for educational demonstration
  [ "$header" == $'\r' ] && break;
##  [ "$header" == $'' ] && break;    # for STDIN/STDOUT educational demonstration
done

if [ -e "$filename" ]
then
#  echo `date` OK $filename on `hostname` >> $log
  echo -e "HTTP/1.1 200 OK\r"
  echo -e "Content-Type: $(/usr/bin/file -bi \"$filename\")\r"
  echo -e "\r"
  /bin/cat "$filename"
else
#  echo "$(date)" ERR $filename on "$(hostname)" >> "$log"
  echo -e "HTTP/1.1 404 Not Found\r"
  echo -e "Content-Type: text/html;\r"
  echo -e "\r"
  echo -e "<h1>File $filename Not Found</h1>"
#  ip=$(awk '/32 host/ { print f } {f=$2}' /proc/net/fib_trie | sort -u | grep -v 127.0.0.1)
#  echo -e "Host: $(hostname), IP: $ip, ver 1.1"
fi
# chmod +x /usr/local/sbin/webd

Ресурсы Web сервера на shell

# mkdir /var/www

# cat /var/www/index.html
<html>
<h1>Hello from corpX</h1>
<img src=img/logo.gif>
</html>
# mkdir /var/www/img
# wget -O /var/www/img/logo.gif http://val.bmstu.ru/unix/Media/logo.gif

Проверка

http://server.corpX.un/

Asterisk AGI

Использование диалоговых окон

ansible-pull-gpo# cat start.sh
#!/bin/bash

on_off() {
        grep -q "$1" "$2" && echo ON || echo OFF
}

if [ -z ${BR+x} ]; then echo -e "Variable BR (branch) is not set, specify, for example\nexport BR=master"; exit 1; fi

apt update || exit 0

apt install dialog ansible git -y

GP_OP_FILE=/usr/local/etc/gpo_options.yml
GP_EX_FILE=/usr/local/bin/ansible-pull-gpo.sh

TEMP_FILE=$(mktemp -t 'XXXX')

touch "$GP_OP_FILE"

dialog  --title "Configurations, Roles and Programs"  --clear --nocancel\
        --checklist "Choose Options" 19 56 15 \
        CONF_RUS_INT: "Russian Interface" "$(on_off CONF_RUS_INT "$GP_OP_FILE")" \
        PROG_THBIRD: "Mail client Thunderbird" "$(on_off PROG_THBIRD "$GP_OP_FILE")" \
        ROLE_ZAB_AG: "Zabbix Agent" "$(on_off ROLE_ZAB_AG "$GP_OP_FILE")" \
        ROLE_OVPN1_CL: "OpenVPN Client" "$(on_off ROLE_OVPN1_CL "$GP_OP_FILE")" \
2>"$TEMP_FILE"

< "$TEMP_FILE" tr " " "\n" > "$GP_OP_FILE"

rm "$TEMP_FILE"

echo -e "\nEND:" >> "$GP_OP_FILE"

echo "/usr/bin/ansible-pull -U http://server.corpX.un/student/ansible-pull-gpo.git -C $BR -e @$GP_OP_FILE" > "$GP_EX_FILE"

chmod +x "$GP_EX_FILE"

##exit 0

echo -e "0 */2 * * * sleep \${RANDOM:0:2}m; $GP_EX_FILE\n@reboot sleep 3m; $GP_EX_FILE" | crontab -

"$GP_EX_FILE"

#apt upgrade -y

#reboot

Использование программы whiptail (Linux)

Использование программы dialog (FreeBSD)

[radio:~] $ cat /usr/local/bin/internet.sh
#!/bin/sh

file=`mktemp -t ''`

dialog  --title "Radio internet"  --clear \
        --checklist "Choose inet for rooms" 19 56 15 \
        1 "Class 1" ON \
        2 "Class 2" ON \
        3 "Class 3" ON \
        4 "Class 4" ON \
        5 "Class 5" ON \
        6 "Class 6" ON \
        7 "Class 7" ON \
        8 "Class 8" ON \
        9 "Class 9" ON \
        10 "Class 10" ON \
        11 "Class 11" ON \
        12 "Class 12" ON 2>$file

case $? in
  0)
        sed -i '' 's/"//g' $file
        for i in `cat $file` 13 50 100 150 200 201 254
        do
                echo 10.5.${i}.0/24
        done > /usr/local/etc/acl/radio_nets.acl
        sudo /etc/rc.d/pf reload
        ;;
esac
rm $file
[radio:~] $ cat /etc/pf.conf
table <radio_nets> persist file "/usr/local/etc/acl/radio_nets.acl"
table <squid_nets> persist file "/usr/local/etc/acl/squid_nets.acl" 

nat on dc0 from <radio_nets> to any -> (dc0)
rdr proto tcp from <squid_nets> to !<radio_nets> port 80 -> 127.0.0.1 port 3128
[radio:~] # grep manager /usr/local/etc/sudoers
%manager  ALL = NOPASSWD: /etc/rc.d/pf reload

Работа с mysql

sql="select uuid from accounts where uuid=\"$person_uuid\""

uuid=`mysql mybd -B --skip-column-names -e "$sql"`

sql="update accounts set uuid=\"$person_uuid\" where uuid=\"$stage_uuid\""

mysql mybd -B --skip-column-names -e "$sql"

Отладка

set +x
set -n
средства_программирования_shell.txt · Last modified: 2024/03/13 08:30 by val