cppmm 19.06.2009 00:15

СкриптыПример скрипта с параметрами.

Роясь на просторах винта нашёл один старый скриптик. писался он во времена, когда я не признавал ничего кроме fluxbox и консоли. Основное назначение - запись дисков из консоли. Но это не важно.

Вспомнился мне этот скрипт, когда его у себя нашёл потому, что из-за способа обработки парметров, принимаемых скриптом(т.е. -h - помощь, -d - директория и т.д.) пришлось как-то поковырять документацию. В принципе, ничего сложного и всё максимально упрощено, но может кому и пригодится подход.

В самом скрипе используется два подхода - приём команды и приём опций. Ну и плюс для совсем уж новичков - работа с функциями.
  1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
#!/bin/bash
#

TMPFILE=/home/cppmm/wtmp/cdrom.iso

# Определение действия.
case $1 in
wr)
FUNC="f_write"
;;
cp)
FUNC="f_copy"
;;
cl)
FUNC="f_clear"
;;
ch)
FUNC="f_check"
;;
wi)
FUNC="f_write_iso"
;;
help)
FUNC="f_help"
;;
*)
FUNC="f_help"
;;
esac

shift

# Определение параметров.
until [ -z $1 ]
do
if [ "$1" = "-d" ]
then
DIR="$2"
shift
fi
if [ "$1" = "-s" ]
then
SPEED="$2"
shift
fi
if [ "$1" = "-o" ]
then
ODISK="$2"
shift
fi
if [ "$1" = "-i" ]
then
IDISK="$2"
shift
fi
if [ "$1" = "-f" ]
then
ISO="$2"
shift
fi
shift
done

# Функйия проверки наличия переменных и оповещения.
f_var_check() {
case "$1" in
v_help)
echo "Для справки: cd.sh help"
exit 0
;;
v_dir)
if [ -z "$DIR" ]
then
echo "Нужно указать директорию, подготовленную для записи."
f_var_check v_help
fi
;;
v_odisk)
if [ -z "$ODISK" ]
then
echo "Нужно указать устройство, производящее запись."
f_var_check v_help
fi
;;
v_idisk)
if [ -z "$IDISK" ]
then
echo "Нужно указать устройство, с которого производится копирование."
f_var_check v_help
fi
;;
v_speed)
if [ -z "$SPEED" ]
then
SPEED="4"
echo "Скорость записи не установленна. По-умолчанию 4"
echo "Продолжить? [y/n]: "
read ANSWER
case $ANSWER in
[nN])
f_var_check v_help
;;
*)
;;
esac
fi
;;
v_eject)
eject -r /dev/${ODISK}
echo "Вставьте записываемый диск и нажмите Enter."
read ready
eject -t /dev/${ODISK}
;;
v_iso)
if [ -z "$ISO" ]
then
echo "Укажите файл образа."
f_var_check v_help
fi
;;
esac
}

# Функция записи дирректории на диск.
f_write() {
f_var_check v_odisk
f_var_check v_dir
f_var_check v_speed
mkisofs -V "Disk" -l -J -R -v -o ${TMPFILE} ${DIR}
f_var_check v_eject
cdrecord -v -dev=/dev/${ODISK} -speed=${SPEED} ${TMPFILE}
rm -f ${TMPFILE}
}

# Функция копирования диска.
f_copy() {
f_var_check v_odisk
f_var_check v_idisk
f_var_check v_speed
dd if=/dev/${IDISK} of=${TMPFILE} bs=2048
f_var_check v_eject
cdrecord -v -dev=/dev/${ODISK} -speed=${SPEED} ${TMPFILE}
rm -f ${TMPFILE}
}

# Функция очистки диска.
f_clear() {
f_var_check v_odisk
cdrecord dev=/dev/${ODISK} -blank=all
}

f_check() {
f_var_check v_dir
echo "Размерв байтах:"
expr `mkisofs -print-size -quiet $DIR` \* 2084
}

# Функция записи iso-образа.
f_write_iso() {
f_var_check v_odisk
f_var_check v_iso
f_var_check v_speed
cdrecord -v -dev=/dev/${ODISK} -speed=${SPEED} ${ISO}
}

# Функция помощи.
f_help() {
echo " Использование: cd.sh ДЕЙСТВИЕ ОПЦИИ"
echo " Действия:"
echo " wr запись директории на диск."
echo " cp копирование с диска на диск."
echo " cl очистка диска."
echo " ch проверка размера будущего образа диска из директории."
echo " wi запись на диск образа."
echo " Опции:"
echo " -d Директория, подготовленная для записи."
echo " -f Файл ISO."
echo " -i Исходный диск."
echo " -o Диск, подготовленный для записи."
echo " -s Скорость записи."
}

$FUNC



P.S. Если вдруг кто захочет использовать этот скрипт в реальной жизни, он не умеет писать dvd(man cdrecord). Просто у меня в те времена не было пишущего dvd. :)


Тэги: bash script
+ 11 -
Похожие Поделиться

Kraplax 19.06.2009 00:21 #
ай-ай-ай!
Каты в таких постах не забываем! Поправил.
NucleoFag 19.06.2009 00:22 #
А я тока тоже хотел добавить! Оперативно!
Kraplax 19.06.2009 00:25 #
Случайное совпадение просто :P
cppmm 19.06.2009 00:23 #
За каты извиняюсь. Форумный я человек. Никак не привыкну. :)
xT 19.06.2009 01:03 #
Еще в блог "Скрипты на bash" перенести бы =)
Kraplax 19.06.2009 01:10 #
о! точно :) проглядели как-то. Думаю у автора нет веских причин, по которым этот пост нужно было бы оставить в персональном блоге.
cppmm 19.06.2009 07:48 #
хм... Вот честно, выбирал же блок "Скрипты на bash", когда постил. Странно, почему не выбралось.
Kraplax 19.06.2009 19:20 #
Да ничего, со всяким бывает. Нам перенести несложно, а вам продолжать писать =)
Kraplax 19.06.2009 20:57 #
Кажется, я понял почему так вышло - наверняка вы действительно запостили изначально именно в блог "Скрипты на bash", вот только когда я правил с катом я сам не состоял в этом блоге. Система попыталась честно выставить правильный блог, и выставила что попало, потому что того что надо не было.
Так что тут моя вина.
cppmm 19.06.2009 23:48 #
Если так, думаю, это стоит запостить багрепортом разработчикам.
NucleoFag 19.06.2009 00:21 #
Клево! А почему не getopts например?
cppmm 19.06.2009 00:24 #
Вернуться бы на несколько лет назад, спросить, почему не getopts, было бы интересно. :) Я же говорю, что здесь просто один из вариантов. Просто тогда, помню, недели две над этим бился.
NucleoFag 19.06.2009 00:27 #
Я кстати за то чтобы выкладывать сюда всякие скрипты, с их обсуждением и допиливанием. Соглась, прогресс бы сразу бы виден был! =)
А у нас тоже лабы были по СПО в универе, с подобными скриптами...
Kraplax 19.06.2009 00:29 #
Кстати да, очень полезно было бы.
Вот тут нехватает, например, задания утилиты записи через переменную - по опыту знаю, что не у всех wodim слинкован на cdrecord. Так что было бы интересно добавить какую-то опцию, что ли. Или, может быть даже проверку.
NucleoFag 19.06.2009 00:32 #
Вот вот! Жаль я совсем уж дрянной кодер, я даже баш весьма посредственно знаю, но насмотревшись на обсуждения я бы полюбому бы научился полезному, что есть мэйнтаргет одна из главных целей ресурса.
cppmm 19.06.2009 00:48 #
Проверку добавить можно. Это довольно легко. Если нужно, могу сделать пример, но в Debian даже в те времена в этом не было надобности.
cppmm 19.06.2009 00:46 #
Возможно, было бы полезно. Но лично мне сложно понять, что стоит выкладывания, а что нет. Ведь всё здесь очень просто и понятно. :)
Kraplax 19.06.2009 00:27 #
Скрипт хорош. Было бы неплохо пояснить некоторые аспекты, например что значит
until < -z $1 >

Почему здесь указан "первый параметр" (я не силен в скриптах, может быть $1 значит не совсем первый параметр, а что-то другое), и зачем там -z?
cppmm 19.06.2009 00:45 #
< -z $var > проверяет, присутствует ли параметр $var. Если подробнее, то конструкция until < -z $var > означает по-русски "пока есть параметр $var, делать". Если параметра нет, цикл завершается.
А $1 используется так, как надо. Смотреть надо на команду shift. Она сдвигает принимаемые скриптом параметры командной строки. Т.е. если я скажу ./script.sh var1 var2, то по умолчанию, var1 - это $1, а var2 - $2. Но если в скрипте после приёма $1, дать команду shift, то для него $1 станет равен var2. Проще говоря, идёт сдвиг вправо, а самый левый параметр отбрасывается.

P.S. Не уверен, что я могу объяснить лучше, чем ABS Guide. :)
Kraplax 19.06.2009 00:58 #
Вроде все правильно сам осилил :)
Kraplax 19.06.2009 00:56 #
Не читая манов интуитивно вроде бы начинаю понимать, что опция -z проверяет "на вшивость" параметр, и если параметр задан неверно (то есть если такого файла нет или параметра просто не задано), то возвращает положительный результат (1, true или что там еще). При этом $1 это первый (а может просто единственный?) параметр, который есть на входе и он постоянно передвигается командой shift.
А вот в функции f_write_iso() - там первые три строчки проверяют заданы ли параметры. Мне интересно - если они не заданы, то проверка ведь просто выдаст предупреждение, тогда как при заданном параметре v_help функция должна наткнуться на exit 0 и выйти. Так вот - если не задать устройство записи, например, то что будет? cdrecord будет-таки вызван или скрипт сам прервется?
cppmm 19.06.2009 07:43 #
Если не задать какой-нибудь из параметров, функция f_var_check() выведет справку(v_help()) и выйдет из программы(exit 0 в v_help()). Т.е. при нехватки любого из параметров(кроме скорости записи, для которого существует значение по умолчанию) скрипт не вызывает cdrecord и выходит.
Kraplax 19.06.2009 00:48 #
И зачем там в конце добавлена $FUNC?
cppmm 19.06.2009 00:52 #
Это собственно то, что будет делать скрипт. Проще говоря, вызов одной из функций, описанных в самом первом case.
Kraplax 19.06.2009 00:59 #
А, теперь понял =) Спасибо =)
xT 19.06.2009 01:14 #
Познавательно +)
xT 19.06.2009 01:20 #
А чем обусловлено использование case в #Определении действия и "тысячи" if`ов в #Определение параметров?
Разве нельзя использовать case и в определении параметров? Там же только $1 проверяется
Kraplax 19.06.2009 02:41 #
Даже если бы было одинаково в обоих вариантах ценность данного скрипта в освещении различных подходов. Конечно, скорее всего автор просто по незнанию (на тот момент) или из-за определенного положения звезд использовал именно такую комбинацию, но все же этот скрипт в качестве учебного пособия, некоего стартапа для новичка будет лучше именно в таком виде.

А если вы попытались как раз обратиться к проблеме оптимизации и доработки скриптов, о которой говорилось выше - то вопрос интересный. Возможно, с case скрипт выглядел бы действительно элегантнее и читался бы удобнее.
xT 19.06.2009 09:34 #
Конечно, скорее всего автор просто по незнанию (на тот момент) или из-за определенного положения звезд использовал именно такую комбинацию

Это вряд ли (даже без ответа автора ниже), ибо в двух других случаях использовался case =)

А пособие хорошее)
cppmm 19.06.2009 07:47 #
case выбирает одно из значений и продолжает выполнение скрипта дальше после esac. Мне же надо было проверить все заданные параметры командной строки, используя shift. Поэтому было выбрано некрасивое решение с тысячью if'ами.
Честно говоря, даже сейчас этот способ видится простейшим выбором для меня. )
xT 19.06.2009 09:33 #
Понял =) познал магию shift`а
aonick 19.06.2009 19:09 #
Есть еще команда getopt для использования в подобных скриптах.

а скрипт хороший :)
cppmm 19.06.2009 23:52 #
Выше я говорил, что тогда я не знал про getopt и изобретал велосипед. :)
Спасибо за "хорошесть". :)
aonick 20.06.2009 00:02 #
Точно - комментарии по диагонали смотрел.
А велосипед замечательная штука, чем чаще изобретаешь, тем больше потом понимания и удовольствия от узнавания уже существующих решений.
aonick 20.06.2009 21:38 #
Кстати похожий по назначению код, но слегка элегантней (взято без изменений из /etc/init.d/network в SUSE):

while < $# -gt 0 >; do
case $1 in
boot|onboot) MODE=onboot ;;
hotplug) MODE=hotplug ;;
manual) MODE=manual ;;
check) CHECK=check ;;
quiet) be_quiet_has_gone ;;
debug) DEBUG=yes ;;
type=*) TYPE=${1#type=} ;;
fake) FAKE=echo ;;
skip=*) SKIP=${1#skip=} ;;
nm) NETWORKMANAGER=yes ;;
netcontrol) NETWORKMANAGER=no ;;
localfs) FS_FILTER=localfs ;;
remotefs) FS_FILTER=remotefs ;;
*) mesg "Unknown option '$1'"
mesg "options: {boot,hotplug,manual,check,debug,type=<typelist>,fake,localfs)"
exit 1 ;;
esac
shift
done
Kraplax 20.06.2009 21:51 #
куски кода вставляются с помощью тега code, а не color. Поправил, но будьте внимательнее в следующий раз
Kraplax 20.06.2009 21:57 #
кстати, что-то было не так в тексте скрипта строке в 17 - заканчивалось на угловую скобку. Уверен что правильно было бы дописать там еще какие-то значения, да вот незнаю какие, поэтому просто закрыл скобку и кавычки - без них скрипт оставался красным из-за битого синтаксиса.
predator 20.06.2009 22:07 #
да и сейчас тут не все ок выглядит