Перевод сборника команд Unix ToolBox. Часть 18 Shell скрипты

473

В большинстве случаев мы пользуемся Bash, хотя есть еще масса более функциональных, но менее популярных приложений для управления компом без графического интерфейса. Но сегодня речь пойдет о том, как упростить жизнь в консоли и не вводить многократно длинные и сложные, но такие необходимые команды. Для решения этой задачи чаще всего используются скрипты. Вот об этом и пойдет речь в 18 главе перевода ?сборника команд Unix ToolBox.

Shell скрипты

Bourne shell (/bin/sh) присутствует во всех Unix системах, соответственно скрипты, написанные на этом языке, будут работать на любой Unix-машине. Для прочтения: man 1 sh.

Основые понятия о shell скриптах
Переменные и аргументы командной строки

Присваивание значений переменным производится следующим образом: variable=value, получить присвоенное значение можно по ссылке $variable.

MESSAGE=»Hello World» # Присвоить переменной строку «Hello World»
PI=3.1415 # Присвоить цифровое значение
N=8
TWON=`expr $N * 2` # Присвоить арифметическое выражение (только целые числа)
TWON=$(($N * 2)) # Другой вариант
TWOPI=`echo «$PI * 2» | bc -l` # Использование bc для операций с плавающей точкой
ZERO=`echo «c($PI/4)-sqrt(2)/2» | bc -l`

Аргументы командной строки:

$0, $1, $2, … # $0 — сама команда(название скрипта)
$# # Кол-во аргументов командной строки
$* # Все аргументы (аналог $@)
Специальные переменные
$$ # ID текущего процесса
$? # Код возврата последней выполненной команды
command
if [ $? != 0 ]; then
echo «command failed»
fi
mypath=`pwd`
mypath=${mypath}/file.txt
echo ${mypath##*/} # Вывести только имя файла
echo ${mypath%%.*} # Полный путь без расширения
var2=${var:=string} # Если var назначена, использовать ее значение, иначе string
# значение string будет присвоено и var и var2.
Конструкции
for file in `ls`
do
echo $file
done
count=0
while [ $count -lt 5 ]; do
echo $count
sleep 1
count=$(($count + 1))
done
myfunction() {
find . -type f -name «*.$1» -print # $1 -первый аргумент функции
}
myfunction «txt»
Простенький скрипт генерирующий файл
MYHOME=/home/colin
cat > testhome.sh << _EOF # Все до символа _EOF, записывается в файл testhome.sh if [ -d "$MYHOME" ] ; then echo $MYHOME exists else echo $MYHOME does not exist fi _EOF sh testhome.sh Еще один пример скрипта на bourne shell

В данном примере, скрипт создает PDF буклет, из XHTML документа:

#!/bin/sh
# Данный скрипт создает книгу в формате PDF, для печати на принтере
if [ $# -ne 1 ]; then # Проверить аргумент
echo 1>&2 «Usage: $0 HtmlFile»
exit 1 # Выход с кодом больше нуля в случае ошибки
fi
file=$1 # Присвоить имя файла из агрумента
fname=${file%.*} # Взять только имя файла
fext=${file#*.} # Взять только расширение
prince $file -o $fname.pdf
pdftops -paper A4 -noshrink $fname.pdf $fname.ps # Создать postscript буклет
cat $fname.ps |psbook|psnup -Pa4 -2 |pstops -b «2:0,1U(21cm,29.7cm)» > $fname.book.ps
ps2pdf13 -sPAPERSIZE=a4 -sAutoRotatePages=None $fname.book.ps $fname.book.pdf
# В Windows используйте #a4 и #None !
exit 0 # Выход с кодом успешного завершения
awk

Awk — это весьма мощьный и полезный язык для обработки текстовой информации. Кучу примеров, без труда можно найти в сети, здесь приведены лишь несколько простых:

awk ‘{ print $2, $1 }’ file # Вывести из файла 2 колонки, поменя из местами
awk ‘{printf(«%5d : %s\n», NR,$0)}’ file # Форматирование вывода с номерами строк
awk ‘{print FNR «\t» $0}’ files # Несколько измененный вариант
awk NF test.txt # Удалить из вывода пустые строки (аналогично grep ‘.’)
awk ‘length > 80’ # Напечатать строки, длинной более 80 символов
sed

Sed — это неинтерактивный строчный редактор, принимает текст с устройства stdin или из текстового файла, выполняет некоторые со строками и выводит в stdout или в файл. Часто применяется в конвейерной обработке данных совместно с другими командами.

sed ‘s/string1/string2/g’ # Заменить string1 на string2
cat ./wrong.txt | sed ‘s/wrong/right/g’ > ./right.txt # Вывести содержимое файла, заменить слова и записать в другой файл
sed ‘s/\(.*\)1/\12/g’ # Модифицировать «строку1» в «строку2»
sed ‘//,//d’ t.xhtml # Удалить строки, начинающиеся с ⁢p>
# И заканчивающиеся

sed ‘/ *#/d; /^ *$/d’ # Удалить комментарии и пустые строки
sed ‘s/[ \t]*$//’ # Удалить символы табуляции
sed ‘s/^[ \t]*//;s/[ \t]*$//’ # Удалить пробелы в начале и конце
sed ‘s/[^*]/[&]/’ # Заключить первый символ в квадратные скобки
sed = file | sed ‘N;s/\n/\t/’ # Порядковый номер в каждой строке
regex — регулярные выражения
[\^$.|?*+() # Специальные символы, остальные символы означают самих себя
\ # Экранирует специальные символы
* # Повтор 0 или 1 раз
. # Любой символ, за исключением символа новой строки
.* # Совпадает 0 или более символов
^ # Начало строки
$ # Конец строки
.$ # Совпадает с одним любым символ в конце строки
^ $ # Совпадает со строкой, состоящей из одного пробела
[^A-Z] # Любые символы, не входящие в диапазон от А до Z
Некоторые полезные команды

Следующие команды могут пригодиться для использования как в скриптах, так и просто из командной строки:

sort -t. -k1,1n -k2,2n -k3,3n -k4,4n # Отсортировать IPv4 ip адреса
echo ‘Test’ | tr ‘[:lower:]’ ‘[:upper:]’ # Смена регистра символов
echo foo.bar | cut -d . -f 1 # Вернет foo
PID=$(ps | grep script.sh | grep bin | awk ‘{print $1}’) # PID запущенного скрипта
PID=$(ps axww | grep [p]ing | awk ‘{print $1}’) # PID процесса ping
IP=$(ifconfig $INTERFACE | sed ‘/.*inet addr:/!d;s///;s/ .*//’) # Linux
IP=$(ifconfig $INTERFACE | sed ‘/.*inet /!d;s///;s/ .*//’) # FreeBSD
if [ `diff file1 file2 | wc -l` != 0 ]; then […] fi # Файл изменен?
cat /etc/master.passwd | grep -v root | grep -v \*: | awk -F»:» \ # Создание файла паролей http passwd
‘{ printf(«%s:%s\n», $1, $2) }’ > /usr/local/etc/apache2/passwd
testuser=$(cat /usr/local/etc/apache2/passwd | grep -v \ # Проверить пользователя в passwd
root | grep -v \*: | awk -F»:» ‘{ printf(«%s\n», $1) }’ | grep ^user$)
)’ /> :& ;: # bash fork bomb :) . Убьет вашу машину ))
tail +2 file > file2 # Удалить первую строку из файла

Я использую этот небольшой трюк, что-бы разом изменить расширение для кучи файлов, например с *.cxx на *.cpp. (советую для начала протемтировать данный пример, без | sh в конце строки.
Тоже самое можно смделать с помощью команды rename, если она присутствует, или с помошью встроенных средст оболочки.

# ls *.cxx | awk -F. ‘{print «mv «$0» «$1″.cpp»}’ | sh
# ls *.c | sed «s/.*/cp & &.$(date «+%Y%m%d»)/» | sh # Копировать файлы *.c в *.c.20080401
# rename .cxx .cpp *.cxx # Переименовать все файлы .cxx в cpp
# for i in *.cxx; do mv $i ${i%%.cxx}.cpp; done # Встроенными средствами