User Tools

Site Tools


qnote:bash

Быстрые заметки по bash

Цикл for

Конструкция.

for VAR in List
do
команда
done

Переменная $VAR принимает значения из списка List.
Цикл выполняется столько раз сколько элементов в списке.

Пример.

for.sh
#!/bin/bash
for i in 1 2 3 4 5 6 7 
do
echo "Print $i"
done
echo "Echo after done"

Результат.

 
kostya@aee3:~/BT$ ./for.sh 
Print 1
Print 2
Print 3
Print 4
Print 5
Print 6
Print 7
Echo after done

В командае не используется переменная которая перебирается в списке, при этом цикл так же будет выполняться.

for.sh
#!/bin/bash
for VAR in 1 2 3 4 5 6 7 
do
echo "Print $i"
done
echo "Echo after done"

Результат.

kostya@aee3:~/BT$ ./for.sh 
Print 
Print 
Print 
Print 
Print 
Print 
Print 
Echo after done

Сложные (с пробелами, спец символами) элементы списка можно задать в кавычках.

for.sh
#!/bin/bash
for i in 1 "2=3+11*345" 3ake "bla bla bla" 5 6 7 
do
echo "Print $i"
done
echo "Echo after done"

Результат.

kostya@aee3:~/BT$ ./for.sh 
Print 1
Print 2=3+11*345
Print 3ake
Print bla bla bla
Print 5
Print 6
Print 7
Echo after done

Передача списка для цикла из файла.

for.sh
#!/bin/bash
f="myfile"
for i in $(cat $f) 
do
echo "Print $i"
done
echo "Echo after done"

Файл с элементами цикла.
Пробел воспринимается как разделитель между элементами, кавычки не работают.

kostya@aee3:~/BT$ cat myfile
q1
w2
e3 e3
"r4r4r4 t5t5t5"

y6

Результат.

kostya@aee3:~/BT$ ./for.sh
Print q1
Print w2
Print e3
Print e3
Print "r4r4r4
Print t5t5t5"
Print y6
Echo after done

Цикл с перебором чисел.

for1.sh
#!/bin/bash
for ((i = 1; i < 10; i++))
do
echo "Print number $i"
done
echo "Echo after fi"

Результат.

kostya@aee3:~/BT$ ./for1.sh
Print number 1
Print number 2
Print number 3
Print number 4
Print number 5
Print number 6
Print number 7
Print number 8
Print number 9
Echo after fi

Цикл while

Конструкция.

while выражение проверяющее условие
do
команда1
done

Команда1 будет выполняться пока выполняется условие.

Пример.

while.sh
#!/bin/bash
VAR1="0"
#
while [ $VAR1 -lt 5 ]
do
echo "VAR1=$VAR1"
VAR1=$[$VAR1 + 1] 
done
echo "Echo after done"

Результат.

kostya@blackpc:~/Dropbox/BT$ ./while.sh
VAR1=0
VAR1=1
VAR1=2
VAR1=3
VAR1=4
Echo after done

if-*

if-then-fi

Конструкция:

if команда1\условие 
then
команда2 
fi
команда0

При этом команда2 сработает только если команда1 выполнилась успешно и без ошибок (в STDERR ничего не передавалось).

Пример.

ifthen-ping.sh
#!/bin/bash
if ping -c 1 -W 1 $1 2>&1 >/dev/null #В случае ошибки STDERR передать в STDOUT и потом все в нулл.   
then 
echo "$1 is reachable"
fi
echo "Echo after fi"

Если пинг успешен, то будет сообщение “$1 is reachable”.
Если нет, то будет выполняться команда идущая после “fi”.

kostya@aee3:~/BT$ ./ifthen-ping.sh 8.8.8.8
8.8.8.8 is reachable
Echo after fi
kostya@aee3:~/BT$ ./ifthen-ping.sh 8.8.8.1
Echo after fi

if-then-else-fi

Конструкция:

if команда1\условие 
then
команда2
else
команда3 
fi

Если команда1 выполнилась без ошибкой, то делаем команду2.
Если с ошибкой, то делаем команду3.

Пример.

ifthen.sh
#!/bin/bash
if ifconfig | grep $1 
then 
echo "I found my wifi interface!!"
else 
echo "Where is my interface?"
fi
echo "Echo after fi"

В системе есть только интерфейс wlp3s0.

kostya@aee3:~/BT$ ./ifthe.sh wlp3s0
wlp3s0    Link encap:Ethernet  HWaddr 74:e5:0b:6e:97:74  
I found my wifi interface!!
Echo after fi
kostya@aee3:~/BT$ ./ifthe.sh wlp3s1
Where is my interface?
Echo after fi

if-then-elseif-then-fi

Конструкция:

if команда1\условие 
then
команда2
elif команда3\условие
then
команда4
fi

Последовательно проверяем несколько условий и при первом совпадении делаем действие.

Пример.
Сравниваем текущее время в секундах (часы-минуты-секунды) с несколькими значениями и выводим одно из сообщений.

to_go_home_or_not_go_home.sh
#!/bin/bash
 
SIX_PM_IN_SEC=$((18 * 3600))
NINE_AM_IN_SEC=$((9 * 3600))
##
CHOUR=$(date +%H)
CMIN=$(date +%M)
CSEC=$(date +%S)
##
CHOUR_IN_SEC=$(($CHOUR * 3600))
CMIN_IN_SEC=$(($CMIN * 60))
##
CTIME_IN_SEC=$((CHOUR_IN_SEC + CMIN_IN_SEC + CSEC))
##
if [ $CTIME_IN_SEC -le $NINE_AM_IN_SEC ]
then
echo "Why so early?"
elif [[ $CTIME_IN_SEC -gt $NINE_AM_IN_SEC   &&  $CTIME_IN_SEC -le $SIX_PM_IN_SEC ]]
then
echo "Keep calm and work"
elif [ $CTIME_IN_SEC -gt $SIX_PM_IN_SEC ]
then
echo "Run Lola Run"
fi

Вывод команды передать в переменую

Передать результат команды в переменную можно двумя способалм:

  • заключить команду в апострофы - MYDATE=`date +%D`
    или
  • заключить команду в конструкцию $() - MYTIME=$(date +%T)

Пример.

cmd_to_var.sh
#!/bin/bash
MYDATE=`date +%D`
MYTIME="$(date +%T)" # Можно в кавычках, можно без.
echo "MYDATE = $MYDATE and MYTIME = $MYTIME"

Результат.

kostya@aee3:~/BT$ ./cmd_to_var.sh 
MYDATE = 07/02/17 and MYTIME = 19:58:56

Примеры скриптов на bash

Показать текущие pps и bps на интерфейсе

Честно подсмотрел у joemiller.

pps

pps.sh
#!/bin/bash
 
INTERVAL="1"  # update interval in seconds
 
if [ -z "$1" ]; then
        echo
        echo usage: $0 [network-interface]
        echo
        echo e.g. $0 eth0
        echo
        echo shows packets-per-second
        exit
fi
 
IF=$1
 
while true
do
        R1=`cat /sys/class/net/$1/statistics/rx_packets`
        T1=`cat /sys/class/net/$1/statistics/tx_packets`
        sleep $INTERVAL
        R2=`cat /sys/class/net/$1/statistics/rx_packets`
        T2=`cat /sys/class/net/$1/statistics/tx_packets`
        TXPPS=`expr $T2 - $T1`
        RXPPS=`expr $R2 - $R1`
        echo "TX $1: $TXPPS pkts/s RX $1: $RXPPS pkts/s"
done

bps

bps.sh
#!/bin/bash
 
 
if [ -z "$1" ]; then
        echo
        echo usage: $0 network-interface
        echo
        echo e.g. $0 eth0
        echo
        exit
fi
 
IF=$1
 
while true
do
        R1=`cat /sys/class/net/$1/statistics/rx_bytes`
        T1=`cat /sys/class/net/$1/statistics/tx_bytes`
        sleep 1
        R2=`cat /sys/class/net/$1/statistics/rx_bytes`
        T2=`cat /sys/class/net/$1/statistics/tx_bytes`
        TBPS=`expr $T2 - $T1`
        RBPS=`expr $R2 - $R1`
        TKBPS=`expr $TBPS / 1024`
        RKBPS=`expr $RBPS / 1024`
        echo "tx $1: $TKBPS kb/s rx $1: $RKBPS kb/s"
done

Бэкап linux сервера через rsync и список файлов отправить на почту

save_san.sh
#!/bin/bash
###
SSHOPT="/usr/bin/ssh -c blowfish"
ROPT="-v -az --delete"
BASE_BUP_DIR="/backup"
BASE_LOG_DIR="/root/bin/log"
BUP_SRV="nas"
SRV="san"
LOG_FILE="$BASE_LOG_DIR/$SRV_bup_log"
CDATE=$(date +%Y%m%d)
CTIME=$(date +%H:%M)
###
echo "$CDATE" > $LOG_FILE
echo "Время начала бэкапа: $CTIME" >> $LOG_FILE
echo "Бэкап $SRV с помощью rsync на $BUP_SRV." >> $LOG_FILE
echo "===============" >> $LOG_FILE
echo "===============" >> $LOG_FILE
echo "Время начала выполнения задания 1: $CTIME" >> $LOG_FILE
rsync $ROPT -e "$SSHOPT" root@san:/etc/ $BASE_BUP_DIR/san/etc | tee -a $LOG_FILE
#
echo "===============" >> $LOG_FILE
echo "Время начала выполнения задания 2: $CTIME" >> $LOG_FILE
rsync $ROPT -e "$SSHOPT" root@san:/root/ $BASE_BUP_DIR/san/root | tee -a $LOG_FILE
#
echo "===============" >> $LOG_FILE
echo "===============" >> $LOG_FILE
echo "Время окончания бэкапа: $CTIME" >> $LOG_FILE
#
mailx -s "Бэкап $SRV" noc@company.name < $LOG_FILE

Локально бекапим linux сервер через rsync

copy_noc1.sh
#!/bin/bash
#backup noc1 to noc1.
 
CDATE=$(date +%Y%m%d) 
ROPT="-v -az --delete"
 
#RSYNC
rsync $ROPT /etc/ /backup/noc1/etc/
rsync $ROPT /root/ /backup/noc1/root/
rsync $ROPT /home/rancid/ /backup/noc1/rancid/
rsync $ROPT /var/www/ /backup/noc1/var_www/
rsync $ROPT /var/log/ /backup/noc1/var_log/
rsync $ROPT /usr/local/viewvc-1.1.26/ /backup/noc1/usr_local_viewvc-1.1.26/
 
#MYSQLDUMP
mysqldump -u USERNAME -pPASSWORD viewvc_db > /backup/noc1/mysql/viewvc_db_$CDATE.sql

Заархивировать данные и скопировать их на FTPS сервер

external_backup.sh
#!/bin/bash
 
CDATE=$(date +%Y%m%d) 
BASE_BACKUP_DIR=/backup
EXT_BACKUP_DIR=/backup/for_ext_bup
 
#TAR
tar -zcvf $EXT_BACKUP_DIR/voip1-$CDATE.tar.gz -C $BASE_BACKUP_DIR voip1 
 
#FTP
lftp -u USERNAME,PASSWORD  some-ftps-server.ru:23322<<EOF-PUT
set ftp:ssl-force true
set ssl:verify-certificate no
lcd $EXT_BACKUP_DIR
cd some-dir-at-ftps-server 
put voip1-$CDATE.tar.gz
exit
EOF-PUT
 
#DELETE OLD BACKUP FILES
find /backup/for_ext_bup/voip1-*.tar.gz  -mtime +30 -delete

Заархивировать netflow данные

tar-backup-netflow-data.sh
#!/bin/bash
 
# Задаем базовые и стартовые значения переменных.
BASE_NFSEN_BACKUP_DATA_DIR=/root/test-nfdump/profiles-data/live
BASE_TAR_DIR=/root/test-nfdump/tar
ROUTER=START-ROUTER
YEAR=START-YEAR
MONTH=START-MONTH
 
# Выводим имена директорий в виде списка которые будут использоваться в цикле архивирования всех месяцев (MONTH=ALL) 
LIST_ONLY_FOLDER_NAME () {
find $BASE_NFSEN_BACKUP_DATA_DIR/$ROUTER/$YEAR -maxdepth 1 -mindepth 1 -type d -printf '%f\n'
}
 
# Формируем справку.
SHOW_HELP () {
  echo "Скрипт $0 предназначен для архивирования netflow данных которые были скописрованы с сервера flow1."
  echo "Данные сворачиваются в архив вида nfcapd-ciso1-201702.tar.bz2."
  echo "Скрипту обзательно надо дать три ключа: \"-r\", \"-y\", \"-m\"."
  echo "Ключ \"-r\" задает роутер, данные которого будут архивироваться."
  echo "Ключ \"-y\" указывает на год за который надо будет брать данные."
  echo "Ключ \"-m\" указывает на месяц за который надо брать данне для добавления в архив."
  echo "Ключ \"-m\" может иметь два значния - конкретный номер месяца (01, 02 и так до 12) или ALL (будут перебираться все месяцы в выбранном годе)."
  echo "Пример: \"$0 -r cisco6 -y 2015 -m {03|ALL}\"."
}
 
# Проверям наличие аргументов у скрипта.                  
if [ $# -eq "0" ];  # Количество переданных скрипту агрументов ($#) равно нулю (значение NO_ARGS)?
then
	  echo "!!!"
	  echo "Ошибка: Скрипт запускается без ключей и аргументов."
	  echo "!!!"
	  SHOW_HELP       # Если да, то показать справку
	  exit        # и выйти 
fi
 
#Работа с ключами. 
while  getopts "r:y:m:" option # Определяем ключи и говорим, что после ключа обязательно должен быть аргумент.
do
  case $option in
    r) ROUTER=$OPTARG;; # Присваеваем переменной значение аргумента
    y) YEAR=$OPTARG;;
    m) MONTH=$OPTARG;;
    *) echo "Выбран недопустимый ключ." # Если введен ключ который мы ранее не определили, то выводим сообщение
    exit;; # и выходим
  esac
done
 
 
 
# Проверяем, что скрипту были переданы три ключа с аргументами. 
# Если значение переменной совпадает со стартовым значением, значит ключ не был задан. 
if [ "$ROUTER" = "START-ROUTER" ]; 
then
	echo "!!!"
	echo "Ошибка: Не задан ключ \"-r\"."
	echo "!!!"
	SHOW_HELP
	exit
elif [ "$YEAR" = "START-YEAR" ];
then
	echo "!!!"
	echo "Ошибка: Не задан ключ \"-y\"."
	echo "!!!"
	SHOW_HELP
	exit	 
elif [ "$MONTH" = "START-MONTH" ];
then
	echo "!!!"
	echo "Ошибка: Не задан ключ \"-m\"."
	echo "!!!"
	SHOW_HELP
	exit
elif [ "$MONTH" = "ALL" ]; # Запускаем цикл если с ключем было передано ALL.
# Будет создано столько архивов, сколько месячных папок выдаст команда LIST_ONLY_FOLDER_NAME.
then 
	for MONTH in `LIST_ONLY_FOLDER_NAME`
	do
	tar -cjvf $BASE_TAR_DIR/nfcapd-$ROUTER-$YEAR$MONTH.tar.bz2 -C $BASE_NFSEN_BACKUP_DATA_DIR $ROUTER/$YEAR/$MONTH
	done
else # Если с ключем -m был передан конкретный номер месяца, то делаем один архив. 
	tar -cjvf $BASE_TAR_DIR/nfcapd-$ROUTER-$YEAR$MONTH.tar.bz2 -C $BASE_NFSEN_BACKUP_DATA_DIR $ROUTER/$YEAR/$MONTH
fi

Скрипт bash tar-backup-netflow-data-via-ssh.sh позволяет сразу скопировать архив на удаленный сервер по ssh.
Это полезно когда на локальном сервере мало место и некуда записать архив.
Перед запуском скрипта на 1.2.3.4 надо скопиловать ssh ключ3, что бы заходить под пользователем username без пароля.

tar-backup-netflow-data-via-ssh.sh
#!/bin/bash
 
# Задаем базовые и стартовые значения переменных.
BASE_NFSEN_BACKUP_DATA_DIR=/data/nfsen_1_3_8_bup/profiles-data/live
BASE_TAR_DIR=/backup/nfsen_bup
ROUTER=START-ROUTER
YEAR=START-YEAR
MONTH=START-MONTH
 
# Выводим имена директорий в виде списка которые будут использоваться в цикле архивирования всех месяцев (MONTH=ALL) 
LIST_ONLY_FOLDER_NAME () {
find $BASE_NFSEN_BACKUP_DATA_DIR/$ROUTER/$YEAR -maxdepth 1 -mindepth 1 -type d -printf '%f\n'
}
 
# Формируем справку.
SHOW_HELP () {
  echo "Скрипт $0 предназначен для архивирования netflow данных которые были скописрованы с сервера flow1."
  echo "Данные сворачиваются в архив вида nfcapd-ciso1-201702.tar.bz2."
  echo "Скрипту обзательно надо дать три ключа: \"-r\", \"-y\", \"-m\"."
  echo "Ключ \"-r\" задает роутер, данные которого будут архивироваться."
  echo "Ключ \"-y\" указывает на год за который надо будет брать данные."
  echo "Ключ \"-m\" указывает на месяц за который надо брать данне для добавления в архив."
  echo "Ключ \"-m\" может иметь два значния - конкретный номер месяца (01, 02 и так до 12) или ALL (будут перебираться все месяцы в выбранном годе)."
  echo "Пример: \"$0 -r cisco6 -y 2015 -m {03|ALL}\"."
}
 
# Проверям наличие аргументов у скрипта.                  
if [ $# -eq "0" ];  # Количество переданных скрипту агрументов ($#) равно нулю (значение NO_ARGS)?
then
	  echo "!!!"
	  echo "Ошибка: Скрипт запускается без ключей и аргументов."
	  echo "!!!"
	  SHOW_HELP       # Если да, то показать справку
	  exit        # и выйти 
fi
 
#Работа с ключами. 
while  getopts "r:y:m:" option # Определяем ключи и говорим, что после ключа обязательно должен быть аргумент.
do
  case $option in
    r) ROUTER=$OPTARG;; # Присваеваем переменной значение аргумента
    y) YEAR=$OPTARG;;
    m) MONTH=$OPTARG;;
    *) echo "Выбран недопустимый ключ." # Если введен ключ который мы ранее не определили, то выводим сообщение
    exit;; # и выходим
  esac
done
 
 
 
# Проверяем, что скрипту были переданы три ключа с аргументами. 
# Если значение переменной совпадает со стартовым значением, значит ключ не был задан. 
if [ "$ROUTER" = "START-ROUTER" ]; 
then
	echo "!!!"
	echo "Ошибка: Не задан ключ \"-r\"."
	echo "!!!"
	SHOW_HELP
	exit
elif [ "$YEAR" = "START-YEAR" ];
then
	echo "!!!"
	echo "Ошибка: Не задан ключ \"-y\"."
	echo "!!!"
	SHOW_HELP
	exit	 
elif [ "$MONTH" = "START-MONTH" ];
then
	echo "!!!"
	echo "Ошибка: Не задан ключ \"-m\"."
	echo "!!!"
	SHOW_HELP
	exit
elif [ "$MONTH" = "ALL" ]; # Запускаем цикл если с ключем было передано ALL.
# Будет создано столько архивов, сколько месячных папок выдаст команда LIST_ONLY_FOLDER_NAME.
then 
	for MONTH in `LIST_ONLY_FOLDER_NAME`
	do
	tar -cjvf - -C $BASE_NFSEN_BACKUP_DATA_DIR $ROUTER/$YEAR/$MONTH | ssh root@1.2.3.4 "cat > $BASE_TAR_DIR/nfcapd-$ROUTER-$YEAR$MONTH.tar.bz2"
	done
else # Если с ключем -m был передан конкретный номер месяца, то делаем один архив. 
	tar -cjvf - -C $BASE_NFSEN_BACKUP_DATA_DIR $ROUTER/$YEAR/$MONTH | ssh username@1.2.3.4 "cat > $BASE_TAR_DIR/nfcapd-$ROUTER-$YEAR$MONTH.tar.bz2"
fi

Потереть данные на диске или флешке

clear-some-important-data.sh
#!/bin/bash
for n in 'seq $2'
do 
    dd if=/dev/urandom of=$1 bs=8b conv=notrunc
done

Пример - затираем раздел /dev/sdb1 ($1) одним проходом ($2).
В случае паранойи количество проходом ставим 7.

[root@aee2 bin]# ./clear-some-important-data.sh /dev/sdb1 1
dd: error writing '/dev/sdb1': No space left on device
977661+0 records in
977660+0 records out
4004495360 bytes (4.0 GB, 3.7 GiB) copied, 409.491 s, 9.8 MB/s

Послать статистику работы Exim на почту

exim_stats.sh
#!/bin/sh
#### Exim Stats ####
log_file="/root/exim_stats_log"
date_minus_1day="$(date --date "-1 days" +'%d.%m.%Y')"
serv_name="$(hostname)"
serv_name_short="$(hostname -s)"
#
echo "=" > ${log_file}
echo "= ${serv_name_short} exim stats. " >> ${log_file}
echo "=" >> ${log_file}
/usr/sbin/eximstats `ls -t /var/log/exim/main.log* | head -n2 | tail -n1`| tee -a ${log_file}
#
mailx -r root@${serv_name} -s "Exim stats for ${date_minus_1day} from ${serv_name_short}" a@b.com < ${log_file}

Переместить логи nginx старше 2 дней и удалить логи старше 60 дней

move_and_delete_old_nginx_logs.sh
#!/bin/bash
 
find /var/log/nginx/ -maxdepth 0 -type f -mtime +2 -exec mv '{}' /var/log/nginx/1_archive_nginx_logs/ \;
find /var/log/nginx/1_archive_nginx_logs/ -type f -mtime +60 -delete

Переместить файл и добавить в имя дату и время перемещения

refresh_rkn_dump.sh
#!/bin/bash
mv /var/www/html/dump/dump.xml /var/www/html/dump/dump.xml.$(date +"%Y%m%d-%H%M")
cp /home/rkn/dump.xml /var/www/html/dump/dump.xml

Переместить логи которые заархивировал logrotate и удалить архивы старше 60 дней

move_and_delete_old_archive.sh
#!/bin/bash
branch_dir=(offce1 office2)
 
for i in ${branch_dir[@]}; do
    mv /var/log/somelog/$i/*.gz /var/log/somelog/1archive-$i/
    find /var/log/somelog/1archive-$i/ -type f -mtime +60 -delete

Посмотреть ip адрес у определенного без\с www

compare_url_ip.sh
#!/bin/sh
url=$1
host $url | head -n 1
host www.$url | head -n 1
qnote/bash.txt · Last modified: 2021/08/12 08:35 (external edit)

Page Tools