В соответствии с соглашениями, имена файлов с shell-скриптами, такими как Bourne shell и совместимыми, имеют расширение .sh. Все стартовые скрипты, которые вы найдете в /etc/rc.d, следуют этому соглашению.
Некоторые разновидности Unix (основанные на 4.2BSD) требуют,
чтобы эта последовательность состояла из 4-х байт, за счет
добавления пробела после ! --
#! /bin/sh.
В shell-скриптах последовательность #! должна стоять самой первой и задает
интерпретатор (sh или
bash). Интерпретатор, в свою
очередь, воспринимает эту строку как комментарий, поскольку она
начинается с символа #.
Если в сценарии имеются еще такие же строки, то они
воспринимаются как обычный комментарий.
#!/bin/bash
echo "Первая часть сценария."
a=1
#!/bin/bash
# Это *НЕ* означает запуск нового сценария.
echo "Вторая часть сценария."
echo $a # Значение переменной $a осталось равно 1.
Эта особенность позволяет использовать различные
хитрости.
#!/bin/rm
# Самоуничтожающийся сценарий.
# Этот скрипт ничего не делает -- только уничтожает себя.
WHATEVER=65
echo "Эта строка никогда не будет напечатана."
exit $WHATEVER # Не имеет смысла, поскольку работа сценария завершается не здесь.
Попробуйте запустить файл README с
сигнатурой #!/bin/more (предварительно
не забудьте сделать его исполняемым).
Внимание: вызов Bash-скрипта с помощью команды sh scriptname отключает
специфичные для Bash расширения, что может привести к появлению
ошибки и аварийному завершению работы сценария.
Почему бы не запустить сценарий просто набрав название файла
scriptname, если
сценарий находится в текущем каталоге? Дело в том, что из
соображений безопасности, путь к текущему каталогу "." не включен в переменную окружения
$PATH. Поэтому необходимо явно указывать
путь к текущему каталогу, в котором находится сценарий, т.е.
./scriptname.
Исключение: блок кода, являющийся частью конвейера,
может
быть запущен в дочернем процессе (subshell-е).
ls | { read firstline; read secondline; }
# Ошибка! Вложенный блок будет запущен в дочернем процессе,
# таким образом, вывод команды "ls" не может быть записан в переменные
# находящиеся внутри блока.
echo "Первая строка: $firstline; вторая строка: $secondline" # Не работает!
# Спасибо S.C.
Аргумент $0
устанавливается вызывающим процессом. В соответствии с
соглашениями, этот параметр содержит имя файла скрипта. См.
страницы руководства для execv
(man execv).
Символ "!", помещенный
в двойные кавычки, порождает сообщение об ошибке, если команда
вводится с
командной строки. Вероятно это связано с тем, что
этот символ интерпретируется как попытка обращения к истории команд. Однако внутри сценариев
такой прием проблем не вызывает.
Не менее любопытно поведение символа "\", употребляемого внутри двойных
кавычек.
С флагом suid, на двоичных исполняемых файлах,
надо быть очень осторожным, поскольку это может быть
небезопасным. Установка флага suid на файлы-сценарии не имеет никакого
эффекта.
Как указывает S.C., даже заключение строки в кавычки, при
построении сложных условий проверки, может оказаться
недостаточным. [ -n
"$string" -o "$a" = "$b"
] в некоторых версиях Bash такая проверка может
вызвать сообщение об ошибке, если строка $string пустая. Безопаснее, в смысле
отказоустойчивости, было бы добавить какой-либо символ к,
возможно пустой, строке: [
"x$string" != x -o "x$a" = "x$b"
] (символ "x" не учитывается).
Слова "аргумент" и
"параметр" очень часто
используются как синонимы. В тексте данного документа, они
применяются для обозначения одного и того же понятия, будь то
аргумент, передаваемый скрипту из командной строки или входной
параметр функции.
Опция -- это аргумент, который управляет поведением сценария
и может быть либо включен, либо выключен. Аргумент, который
объединяет в себе несколько опций (ключей), определяет
поведение сценария в соответствии с отдельными опциями,
объединенными в данном аргументе..
Скрытыми считаются файлы, имена которых начинаются с точки,
например, ~/.Xdefaults. Такие файлы
не выводятся простой командой ls, и не могут быть удалены командой
rm -rf *. Как правило,
скрытыми делаются конфигурационные файлы в домашнем каталоге
пользователя.
Команда tar czvf archive_name.tar.gz
*включит в архив все скрытые файлы (имена
которых начинаются с точки) из вложенных
подкаталогов. Это недокументированная "особенность" GNU-версии
tar.
Она реализует алгоритм симметричного блочного шифрования, в
противоположность алгоритмам шифрования с "открытым ключом", из которых широко
известен pgp.
Демон -- это некий фоновый процесс, не
привязанный ни к одной из терминальных сессий. Демоны
предназначены для выполнения определенного круга задач либо
через заданные промежутки времени, либо по наступлению какого
либо события.
Слово "демон"
("daemon"), в греческой
мифологии, употреблялось для обозначения призраков, духов,
чего-то мистического, сверхестественного. В мире Unix -- под
словом демон подразумевается процесс, который "тихо"
и "незаметно" выполняет свою работу.
EBCDIC (произносится как "ebb-sid-ic") -- это аббревиатура от
Extended Binary Coded Decimal Interchange Code (Расширенный
Двоично-Десятичный Код Обмена Информацией). Это формат
представления данных от IBM, не нашедший широкого применения.
Не совсем обычное применение опции conv=ebcdic -- это использовать dd для быстрого и легкого, но слабого,
шифрования текстовых файлов.
cat $file | dd conv=swab,ebcdic > $file_encrypted
# Зашифрованный файл будет выглядеть как "абракадабра".
# опция swab добавлена для внесения большей неразберихи.
cat $file_encrypted | dd conv=swab,ascii > $file_plaintext
# Декодирование.
Дополнительную информацию по записи компакт-дисков, вы
найдете в статье Алекса Уизера (Alex Wither): Creating CDs, в октябрьском выпуске
журнала Linux Journal за 1999 год.
Более корректно (с технической точки зрения) следовало бы
сказать, что операция подстановки команды заключается в
получении вывода от команды (со stdout) и присвоения результата выполнения
переменной, с помощью оператора =.
При использрвании дескриптора с
номером 5 могут возникать проблемы. Когда Bash
порождает дочерний процесс, например командой exec, то дочерний процесс наследует дескриптор 5
как "открытый" (см. архив почты Чета Рамея (Chet
Ramey), SUBJECT: RE: File descriptor 5 is held
open) Поэтому, лучше не использовать этот
дескриптор.
Поскольку с помощью sed, awk и grep обрабатывают
одиночные строки, то обычно символ перевода строки не
принимается во внимание. В тех же случаях, когда производится
разбор многострочного текста, метасимвол "точка"
будет соответствовать символу перевода строки.
#!/bin/bash
sed -e 'N;s/.*/[&]/' << EOF # Встроенный документ
line1
line2
EOF
# OUTPUT:
# [line1
# line2]
echo
awk '{ $0=$1 "\n" $2; if (/line.1/) {print}}' << EOF
line 1
line 2
EOF
# OUTPUT:
# line
# 1
# Спасибо S.C.
exit 0
Подстановка таких имен файлов возможна, но только
при условии, что символ точки будет явно присутствовать в
шаблоне.
~/[.]bashrc # Не будет соответствовать имени ~/.bashrc
~/?bashrc # То же самое.
# Метасимволы не могут соответствовать символу точки при подстановке имен файлов.
~/.[b]ashrc # Имя ~./bashrc будет соответствовать данному шаблону
~/.ba?hrc # Аналогично.
~/.bashr* # Аналогично.
# Установка ключа "dotglob" отключает такое поведение интерпретатора.
# Спасибо S.C.
Имеет тот же эффект, что и именованные каналы (временный файл),
фактически, именованные каналы некогда использовались в
операциях подстановки процессов.
Herbert
Mayer определяет рекурсию, как "...описание алгоритма с помощью более простой
версии того же самого алгоритма..." Рекурсивной
называется функция, которая вызывает самого себя.
Слишком глубокая рекурсия может вызвать крах сценария.
#!/bin/bash
# Осторожно: Этот сценарий может подвесить систему!
# Если вам повезет, то вы получите segfault прежде, чем будет исчерпана вся доступная память.
recursive_function ()
{
(( $1 < $2 )) && recursive_function $(( $1 + 1 )) $2;
# Увеличивать 1-й параметр до тех пор,
#+ пока он не станет равным, или не превысит, второму параметру.
}
recursive_function 1 50000 # Глубина рекурсии = 50,000!
# Наиболее вероятное развитие событий -- segfaults (в зависимости от объема стека).
# Рекурсия такой глубины может "обрушить" даже программу, написанную на C,
#+ по исчерпании памяти, выделенной под сегмент стека.
# Спасибо S.C.
echo "Эта строка не должна быть выведена на экран."
exit 0 # Этот сценарий завершается аварийно (в лучшем случае).
# Thanks, Stephane Chazelas.
Каталог /dev содержит специальные
файлы -- точки монтирования физических и виртуальных устройств.
Они занимают незначительное пространство на диске.
Некоторые из устройств, такие как /dev/null, /dev/zero
или /dev/urandom -- являются
виртуальными. Они не являются файлами физических устройств,
система эмулирует эти устройства программным способом.
Блочное
устройство читает и/или пишет данные целыми
блоками, в отличие от символьных устройств, которые читают
и/или пишут данные по одному символу. Примером блочного
устройства может служить жесткий диск, CD-ROM. Примером
символьного устройства -- клавиатура.
Указание кода завершения за пределами установленного
диапазона, приводит к возврату ошибочных кодов. Например,
exit 3809 вернет код
завершения, равный 225.
В некоторых ранних версиях Unix предполагалось размещение
корневого раздела файловой системы на очень быстром диске
небольшой емкости, а второй диск имел больший объем, хотя и
уступал первому по быстродействию, и на нем размещался раздел
/usr и другие разделы. Таким образом,
наиболее часто используемые программы и утилиты располагались
на маленьком, но быстром диске, в каталоге /bin, а все остальные программы размещались на
более медленном диске в каталоге /usr/bin.
Подобному разделению подвергались каталоги /sbin и /usr/sbin,
/lib и /usr/lib, и так далее.