Для решения задачи по синхронизации данных между двумя машинами, в ситуации
когда изменения могут появиться на каждом из компьютеров, прекрасно подходит
утилита unison (http://www.cis.upenn.edu/~bcpierce/unison/). При синхронизации
между удаленными машинами в качестве транспорта может использоваться ssh. При
обнаружении конфликтов, например, когда на обоих машинах отредактирован один и
тот же файл, unison пытается разрешить конфликт автоматически, а если это не
удается предоставляет пользователю интерфейс для принятия решения.
Устанавливаем unison.
Fedora/RHEL/CentOS:
sudo yum install unison |
Debian/Ubuntu:
sudo apt-get install unison |
FreeBSD:
$ cd /usr/ports/net/unison/ && make install |
Синхронизируем две локальные директории:
unison /test1 /test2 |
В процессе будет выводиться статистика и задаваться вопросы, касающаяся
синхронизации и разрешения конфликтов, направление копирования будет указано стрелкой.
Для синхронизации с удаленной директорией необходимо указать:
unison /test1 ssh://testserver.test.ru//test1 |
Чтобы выполнить синхронизацию автоматически, без интерактивного взаимодействия
с пользователем необходимо использовать опцию «-batch». В случае конфликта,
выполнение будет прервано с выводом соответствующего уведомления.
Для определения сложной политики синхронизации можно создать файл конфигурации
с определением параметров.
Например, создаем файл ~/.unison/test.prf:
# Определяем список директорий, которые будут синхронизированы root = /home/project root = /mnt/NFS/home/project # Указываем сохранять права доступа и владельца owner = true times = true # Определяем список поддиректорий, которые нужно синхронизировать, остальное игнорируем: path = cgi-bin path = htdocs path = conf # Определяем маски для файлов, которые не нужно синхронизировать ignore = Name .htaccess ignore = Name *~ ignore = Name .*~ ignore = Path conf/project.conf ignore = Path htdocs/rrd ignore = Path htdocs/mon ignore = Name *.o ignore = Name *.tmp ignore = Name *.log ignore = Name *.gz ignore = Name *.iso ignore = Name {,.}*{.old} # Копируем в резервные копии изменяемых файлов в отдельную директорию backup = Name * backups = true backupdir = /home/project/backup # Определяем свою команду для отображения отличий между копиями файлов при конфликте #diff = diff -y -W 79 --suppress-common-lines # Сохраняем лог с результатами работы в отдельном файле log = true logfile = ./sync.log |
При необходимости синхронизировать описанные в файле конфигурации директории, выполняем:
unison test |
Существует множество фичей упрощающих жизнь системному администратору. Различные системы удаленного управления позволяют установить ОС на девственно-чистый сервер и сегодня это совсем не проблема. Даже наличие второго винчестера превращает проблему переустановки операционки в банальность. Поэтому в этой статье рассмотрим самый суровый из случаев: пусть на сервере имеется только один полностью разбитый винчестер, а наша задача — удалённо переустановить ОС.
Удивлённо поднимем брови, умиляясь тому, как гибка наша любимая операционка, засучим рукава и приступим к делу.
В основе данного метода лежит идея о том, что мы можем использовать SWAP-раздел для установки временной операционной системы, а когда она встанет на ноги — заняться основной. Главное и единственное, что нам нужно — это своп размером не менее 420 Мб (именно столько занимает lenny со всем необходимым).
В статье используются следующие допущения:
— у вас стоит дебиан, и ставить вы планируете дебиан,
— используется grub установленный в MBR.
1. превращаем swap-раздел в ext3;
2. устанавливаем на него чистую ОС;
3. перезагружаемся в нее;
4. делаем нужные изменения на основном разделе;
5. копируем чистую ОС из временного в основной раздел;
6. загружаемся с основного раздела, включаем swap.
Первое, что мы сделаем — убедимся, есть ли у нас этот своп-раздел вообще:
# free -m ... Swap: 470 0 470 |
Как видим — есть, и размер (отображается в Мб) вполне удовлетворяет требованиям. Осталось выяснить, как у нас разбит диск:
# fdisk -l /dev/sda ... Device Boot Start End Blocks Id System /dev/sda1 * 1 462 3710983+ 83 Linux /dev/sda2 463 522 481950 5 Extended /dev/sda5 463 522 481918+ 82 Linux swap / Solaris |
Видно, что на sda1 — текущая ОС, на sda5 — своп. Запутаться сложно, но всякое бывает.
Отключаем своп:
# swapoff -a |
Убедиться, что мы его выключили, можно выполнив всё тот же free:
# free ... Swap: 0 0 0 |
Обновим нашу таблицу разделов:
# fdisk /dev/sda Command (m for help): t Partition number (1-5): 5 Hex code (type L to list codes): 83 Changed system type of partition 5 to 83 (Linux) Command (m for help): w The partition table has been altered! WARNING: Re-reading the partition table failed with error 16: Устройство или ресурс занято. The kernel still uses the old table. The new table will be used at the next reboot. Syncing disks. |
Нам заботливо сообщили, что ядро не увидит изменений до перезагрузки, но нам это пока и не нужно. Теперь самое время подготовить файловую систему на нашем старом новом разделе. Например, ext3:
# mke2fs -j /dev/sda5 Writing inode tables: done Creating journal (4096 blocks): done |
Примонтируем раздел куда-нибудь и на этом его подготовка будет закончена.
# mkdir /mnt/temp # mount /dev/sda5 /mnt/temp # df -h Файловая система Разм Исп Дост Исп% смонтирована на /dev/sda1 3,5G 600M 2,8G 18% / ... /dev/sda5 456M 11M 422M 3% /mnt/temp |
Здесь нужно заметить, что временной она является только по своему местоположению. Чтобы дважды не прогонять все действия по сборке чистой системы в дальнейшем мы просто скопируем её на основной раздел.
Используем отличное средство для получения минимальной установки — debootstrap. Здесь и далее мы будем считать что проблем с интернетом на сервере нет (иначе какой же он после этого сервер ?), поэтому выкачиваем всё из репозитория.
# aptitude install debootstrap ... Настраивается пакет debootstrap (1.0.10lenny1) ... |
Данной утилите достаточно передать четыре параметра: желаемая архитектура, название релиза, директория установки и ссылка на полное зеркало. Архитектуру можно определить по выводу `uname -a`, дистрибутив выбираем на свой вкус, директория в данном случае та, куда мы смонтировали наш раздел, а ссылку на зеркало можно взять здесь: http://www.debian.org/mirror/list. Получается, что строка запуска выглядит примерно так:
# debootstrap --arch i386 lenny /mnt/temp http://ftp.ru.debian.org/debian/ |
После нажатия enter начнется процесс загрузки и установки пакетов, при достаточно среднем интернет-соединении (~10 Мбит) на это уходит порядка 5-10 минут — я даже не успел допить свой чай. В конце вы увидите сообщение о том, что система успешно установлена:
I: Base system installed successfully. |
Теперь начинается одна из самых ответственных процедур: нам нужно правильно сконфигурировать новую систему. Любому сис-админу, наверное, снились кошмары о том, как он теряет удаленный контроль над машиной, да и в конце концов всё это мы затевали именно для того, чтобы не ехать в дата-центр. Поэтому отложим кружку кофе и сосредоточимся.
Сначала скопируем все важные настройки. Наверное, у каждого найдутся достаточно важные файлы, которые лежат не там где положено. У меня, к примеру, есть некий /etc/rc.routes со всеми нестандартными маршрутами. Главное не забыть ничего. Приводить тут какой-либо список, мне кажется, совершенно бессмысленно, но у меня это выглядит примерно так:
# cp /etc/{resolv.conf,hosts,rc.local} /mnt/temp/etc # cp /etc/network/interfaces /mnt/temp/etc/network # cp /etc/your-stuff /mnt/temp/etc |
В fstab напишем самое необходимое — proc и наш корневой раздел:
# cat > /mnt/temp/etc/fstab << "#EOF" > proc /proc proc defaults 0 0 > /dev/sda5 / ext3 errors=remount-ro 0 1 > #EOF |
Теперь смонтируем dev-окружение, перейдем в чрут нашей временной системы и сразу примонтируем proc:
# mount --bind /dev /mnt/temp/dev # chroot /mnt/temp /bin/bash # mount -t proc proc /proc |
Очевидно нам понадобится менеджер пакетов, думаю рассказывать о его настройке отдельно не нужно.
# wget http://debian.soar.name/sources.list -O /etc/apt/sources.list # aptitude update |
Настроим часовой пояс:
# dpkg-reconfigure tzdata |
Также нам понадобятся следующие пакеты:
# aptitude install locales # dpkg-reconfigure locales # aptitude install console-data # aptitude install ssh # aptitude install sudo |
Сразу же, чтобы не забыть, создадим пользователя и назначим ему пароль, иначе в ssh нас потом не пустят:
# adduser --ingroup users soar # visudo |
Теперь переустановим загрузчик. Сначала необходимо создать все файлы загрузчика на новом диске:
# aptitude install grub # grub-install /dev/sda |
После чего необходимо инициализировать МБР на загрузку с нашего нового раздела. Для этого всё там же, в чруте, войдем в консоль граба и напишем следующее:
# grub grub> root (hd0, Possible partitions are: Partition num: 0, Filesystem type is ext2fs, partition type 0x83 Partition num: 4, Filesystem type is ext2fs, partition type 0x83 |
Своеобразный автокомплит по табу подскажет нам, какие разделы есть в нашем распоряжении. Как видим всё на единицу меньше чем в названии в системе. Инициализируем загрузку с нашего sda5:
grub> root (hd0,4) Filesystem type is ext2fs, partition type 0x83 grub> setup (hd0) ... Done. grub> quit |
Загрузчик установлен куда нужно. Теперь выберем и установим подходящее ядро:
# aptitude search linux-image # aptitude install linux-image-2.6.26-2-686 |
В ходе установки нас спросят «Create a symbolic link to the current kernel image?», на что мы ответим утвердительно. Так же сообщат, что мы устанавливаем ядро, требующее от загрузчика поддержку initrd, и уточнят, не передумали ли мы.
Отвечаем «Нет» и установка заканчивается. Осталось обновить меню загрузчика:
# update-grub Found kernel: /boot/vmlinuz-2.6.26-2-686 Updating /boot/grub/menu.lst ... done |
Выходим из чрута, собираем нервы в кулак и отправляем сервер в первую перезагрузку:
# exit # reboot |
Если все было сделано правильно — машина перезагрузится в нашу временную систему. Мы можем зайти в ssh как пользователь, которого мы только что добавили.
Форматируем и монтируем наш старый раздел:
# mke2fs -j /dev/sda1 Writing inode tables: done Creating journal (16384 blocks): done Writing superblocks and filesystem accounting information: done # mkdir /mnt/temp # mount /dev/sda1 /mnt/temp |
К слову, на этом этапе можно провести и обслуживание диска: например переразбить основной раздел и проверить файловую систему.
Остается скопировать нашу чистую ОС на основной раздел:
# cp -a -x / /mnt/temp/ |
Обновляем fstab. На этот раз причешем его по всем правилам:
# cat > /mnt/temp/etc/fstab << "#EOF" > # /etc/fstab: static file system information. > # > # > proc /proc proc defaults 0 0 > /dev/sda1 / ext3 defaults,errors=remount-ro 0 0 > #EOF |
В очередной раз нужно обновить граб. На этот раз — для загрузки уже с нашего основного раздела:
# mount --bind /dev /mnt/temp/dev # chroot /mnt/temp/ /bin/bash # grub-install /dev/sda # grub grub> root (hd0,0) Filesystem type is ext2fs, partition type 0x83 grub> setup (hd0) Checking if "/boot/grub/stage1" exists... yes Checking if "/boot/grub/stage2" exists... yes Checking if "/boot/grub/e2fs_stage1_5" exists... yes Running "embed /boot/grub/e2fs_stage1_5 (hd0)"... 17 sectors are embedded. succeeded Running "install /boot/grub/stage1 (hd0) (hd0)1+17 p (hd0,0)/boot/grub/stage2 /boot/grub/menu.lst"... succeeded Done. grub> quit # update-grub Updating /boot/grub/menu.lst ... done |
Тут стоит отметить, что у меня в этом месте, в отличие от первого случая, menu.lst обновляться отказался, и там по-прежнему оставались ссылки на sda5. Почему это происходит — я так и не разобрался, поэтому вручную подредактировал этот файл:
# sed -i -e 's/sda5/sda1/g' /boot/grub/menu.lst # sed -i -e 's/(hd0,4)/(hd0,0)/g' /boot/grub/menu.lst |
Выходим из чрута и делаем вторую перезагрузку:
# exit # reboot |
После перезагрузки можно убедиться, что мы снова на родном основном разделе:
# df -h Файловая система Разм Исп Дост Исп% смонтирована на /dev/sda1 3,5G 436M 2,9G 13% / |
Остается создать и включить своп:
# fdisk /dev/sda Command (m for help): t Partition number (1-5): 5 Hex code (type L to list codes): 82 Changed system type of partition 5 to 82 (Linux swap / Solaris) ... The new table will be used at the next reboot. Syncing disks. # cat >> /etc/fstab << "#EOF" > /dev/sda5 none swap sw 0 0 > #EOF # mkswap /dev/sda5 # swapon -a |
Убедимся что всё нормально:
# free -m Swap: 470 0 470 |
Ну и в конце, если вы редактировали /boot/grub/menu.lst врукопашную — стоит все-таки запустить скрипт его обновления еще раз:
# update-grub Updating /boot/grub/menu.lst ... done |
Данный способ безусловно не самый простой путь переустановки системы, однако, во многих случаях, он становится единственно возможным. Тем более вся процедура занимает около 25 минут, поэтому если ваш ДЦ не через дорогу, то в любом случае выходит совсем неплохая экономия времени. Получилось на удивление много букв — я пытался расписать подробно и понятно, но на самом деле операция простая и достаточно быстрая.
GNU find является одной из наиболее часто используемых программ. На первый взгляд опции find и их синтаксис выглядят слегка непонятными. Однако, немного попрактиковавшись с find, вы сможете быстро и без труда находить любой файл в вашей системе. Чтобы помочь вам начать работать с find, рассмотрите предлагаемые десять способов её использования.
Имейте ввиду, что не все версии find одинаковы, и та, которую вы используете в Linux, будет отличаться от версий для Mac, BSD или Solaris. В основном синтаксис одинаков во всех версиях, но местами встречаются небольшие различия.
Давайте начнём с простого. Если вам известно имя файла, но вы не знаете точно в каком каталоге он расположен, синтаксис find будет предельно прост. Просто сообщите find имя искомого файла:
find -name имя_файла |
Если файл с именем filename существует, то команда find покажет местоположение файла или файлов, которые соответствуют этому имени, следующим образом:
jzb@kodos:~$ find -name filename ./projects/filename jzb@kodos:~$ |
Иногда при поиске файла бывает нужно использовать его дополнительные атрибуты в качестве критерия поиска, а не только имя. Например, размер файла. Например, когда в вашей системе заканчивается свободное место в каком-то дисковом разделе и вам необходимо узнать, какие файлы занимают драгоценное дисковое пространство. При помощи find вы можете отыскать такие файлы и уже потом решить, за счёт чего можно высвободить необходимое дисковое пространство.
Для такого случая у find имеется опция -size, принимающая в качестве параметра размер, являющийся критерием поиска. Размер можно указывать начиная с байтов (b), заканчивая гигабайтами (G). Например, чтобы выполнить поиск файлов размером 100 килобайт, можно использовать команду:
find -size 100k |
Однако такой вариант может не подойти в нашем случае. Более подходящим будет поискать файлы размеров больше (или меньше) заданного. Чтобы выполнить такой поиск, просто добавьте «+» или «-» к размеру, и find будет искать файлы большего или меньшего размера соответственно, чем указан. Например, следующая команда найдёт все файлы размеров более 100 килобайт:
find -size +100k |
а эта — менее, чем 100 килобайт:
find -size -100k |
Также, вы можете попросить find найти все пустые файлы:
find -empty -type f |
Обратите внимание на указанную опцию -type с параметром «f», которая указывает find искать только обычные файлы. Если не указать это, то find выведет также и пустые каталоги.
Другой, часто используемый, вариант поиска — поиск по принадлежности файла какому-то пользователю или даже по его отсутствию. Например, вы переместили какие-то файлы в другую систему или же удалили какого-то пользователя, вероятно сделав файлы «сиротами». Отыскать такие файлы-сироты можно простой командой:
find -nouser |
Для поиска файлов, принадлежащих какому-то конкретному пользователю, существуют опции -user и -uid. Первая опция принимает как имя пользователя, так и его идентификатор, а вторая — только идентификатор. Например, если мне нужно будет найти все файлы, владельцем которых я являюсь, я воспользуюсь одной из команд:
find -user jzb find -user 1000 find -uid 1000 |
Также, вам может понадобиться найти файлы принадлежащие пользователю А или пользователю Б. Для этого необходимо объединить два условия поиска при помощи оператора «-o»:
find -user root -o -user www-data |
Такая команда будет искать файлы, владельцем которых является пользователь root или же пользователь www-data. Если же, например, вы хотите найти файлы, владельцем которых пользователь не является, используйте оператор «-not»:
find -not -user www-data |
Естественно, операторы работают и с другими опциями. К примеру, следующая команда найдёт файлы, владельцем которых является www-data и которые размером не более ста килобайт:
find -user www-data -not -size +100k |
Ещё один способ использования find — поиск файлов, принадлежащих какой-то группе пользователей. Для этого используется опция «-group», параметром которой должно быть имя группы или её идентификатор. Например:
find -group admin |
В повседневной жизни вы, вероятней всего, будете комбинировать эту опцию с другими. Например, если вам нужно отыскать файлы, принадлежащие определённому пользователю и группе.
Иногда у вас может возникать необходимость найти файлы, доступные для записи кому угодно или файлы, имеющие какие-либо другие «плохие» разрешения. Подобный поиск find может осуществлять при помощи различных опций. Простейшие из них — это операторы -readable, -writable и -executable, которые работают применительно к пользователю, запустившему find. Имейте ввиду, что в слишком древних версиях find эти опции отсутствуют.
Другой способ искать файлы определённым режимом доступа — использование опции -perm, позволяющей точно определять права доступа искомых файлов. Например, если вы хотите найти файлы, биты выполнения которых установлены для владельца и группы, используйте команду:
find -type f -perm -110 |
Здесь параметр «110» сообщает find набор битов доступа, а «-» заставляет игнорировать все остальные. Таким образом, если файл имеет ко всему прочему установленные биты чтения и записи, он также будет соответствовать критерию поиска, поскольку для find важно лишь то, что установлены указанные биты выполнения.
Если вам необходимо точное совпадение с указанным режимом доступа, то уберите опцию «-».
А что, если вам необходимо найти файлы, исполняемые владельцем или группой? В это случае вместо «-» используйте «/»:
find -type f -perm /110 |
Поиск по правам доступа часто пригождается, хотя и не лишён некоторой сложности, и вам может потребоваться какое-то время, прежде, чем вы привыкните к его синтаксису. Особенно это касается новичков, которые ещё толком не разобрались с механизмом битов доступа файлов. В этом случае чтение man-страницы find особенно рекомендуется.
Иногда вам может потребоваться использование регулярных выражений, чтобы определить критерии поиска. И find поддерживает их даже в большей степени, чем вы, возможно, ожидали. find не только поддерживает использование регулярных выражений, но и позволяет использовать различные их типы. Тип регулярного выражения можно определить при помощи опции -regextype, которая принимает параметры posix-awk, posix-egrep и тому подобные. В man-странице вы найдёте полный перечень поддерживаемых типов регулярных выражений вашей версией find.
Небольшой пример. Скажем, вам нужно найти файлы, имеющие расширения «.php» и «.js». Такое можно осуществить следующей командой:
find -regextype posix-egrep -regex '.*(php|js)$' |
Выглядит страшновато, не так ли? Эта команда говорит find использовать синтаксис регулярных выражений egrep (-regextype posix-egrep), а затем сообщает само регулярное выражение. Выражение обрамлено одинарными кавычками, чтобы оболочка не пыталась по-своему интерпретировать спецсимволы, использующиеся в выражении. В самом выражении «.*» означает любой символ, повторяющийся ноль или более раз. Часть выражения «(php|js)» сообщает о необходимости искать «php» или «js» (символ вертикальной черты используется для определения оператора «или»). И, наконец, знак доллара в конце выражения сообщает о том, что предыдущая часть выражения должна искаться в конце строки.
Так же, как и с правами доступа, регулярные выражения можно комбинировать.
Что, если вам понадобится найти файлы, основываясь на их возрасте? Иногда бывает, что знаешь, в каком промежутке времени файл был создан, а всё остальное — позабылось. Или же, вам может понадобиться отыскать какие-то старые файлы, которые пора удалить. В общем, причин может быть куча.
find в полном объёме умеет работать со временем, позволяя искать по времени последнего доступа к файлу (-atime), времени последнего изменения файла (-mtime), или по времени его создания (-сtime).
Например, давайте все найдём файлы, которые были изменены за последние два дня:
find -mtime +2 |
Параметры опций, работающих со временем, можно интерпретировать как «N раз по 24 часа» и в действительности означают промежуток времени. Если вы передадите find опцию «+1», то она поймёт это как «не менее, чем 24 часа назад, но не более, чем 48».
Эти опции вы также можете комбинировать, если нужно отыскать файлы, временные критерии поиска находятся в каком-то промежутке. Так, команда
find -mtime +2 -mtime -5 |
означает «два или более дня назад, но не более пяти дней назад».
Иногда бывает нужно найти файлы, изменённые за последние 24 часа, и в этом случае рассмотренные опции *time по понятным причинам не подойдут. Однако, на этот случай, у find припасены специальные опции -amin, -cmin, -mmin, которые работают подобно выше рассмотренным, с той разницей, что в качестве параметров они принимают минуты, а не сутки. Так что, если вам нужно найти какие-то файлы, изменённые, например, в течение рабочего дня — это те самые опции, которые вам помогут.
Иногда find выдаёт намного больше результатов поиска, чем вам нужно. При помощи опции -maxdepth вы можете ограничить find таким образом, чтобы она не «зарывалась» слишком глубоко. Например, если вы хотите найти все файлы c расширением «js» в каталоге wordpress, можно воспользоваться командой:
find wordpress -name '*js' |
Но что, если вас интересуют файлы лишь из каталога верхнего уровня? Нет проблем: ограничьте описк при помощи опции -maxdepth:
find wordpress -maxdepth 1 -name '*js' |
Такая команда заставит искать find только в каталоге wordpress, не заходя в подкаталоги, которые в нём содержатся. Если вы хотите поискать в этих подкаталогах, но не соваться глубже — увеличьте параметр опции -maxdepth на единицу и т. д.
Действия над найденными файлами
Итак, вы нашли то, что искали. Что вы будете делать с найденным? Используя xargs или опцию find -exec, можно выполнять необходимые действия с найденными файлами.
Давайте представим, что вы хотите сменить владельца каких-то файлов с root на www-data. Для начала нужно все эти файлы найти, а затем уж сменять их владельца. Смена владельца вручную по списку, полученному от find звучит как-то скучно. Всё же, лучшим решением будет использовать опцию -exec:
find -user root -exec chown www-data {} \; |
Такая команда заставляет find передавать пути всех найденных файлов утилите chown, которая и будет изменять владельца файлов. Легко и просто!
Знание возможностей утилиты find является обязательным для всех пользователей Linux, которые хотят освоить свою систему. Когда используется рабочий стол, вы можете обойтись без утилиты find, но при администрировании системы вам нужно иметь свои приемы применения утилиты find. Если вы собираетесь использовать параметры -exec и xargs для внесения изменений в файлы или удаления файлов, сначала сделайте один или пару тестов с тем, чтобы убедиться, что команда работает так, как ожидается.
В ходе этой статьи мы разберем как добавлять ссылки на избранные программы в контекстное меню рабочего стола Windows или «Моего компьютера».
Инструкция разделена на 2 части:
1. Создание каскадных меню в контекстном и добавление ярлыков.
2. Добавление функциональности ярлыкам путем их регистрации.
1. Откройте редактор реестра (напишите «regedit» в строке «Выполнить» или строке поиска меню «Пуск» и нажмите Enter).
2. Перейдите в следующую ветку:
HKEY_CLASSES_ROOT\Directory\Background\shell |
Если Вы хотите добавить каскадное меню в контекстое меню «Моего компьютера», тогда перейти нужно в эту ветку:
HKEY_CLASSES_ROOT\CLSID\{20D04FE0-3AEA-1069-A2D8-08002B30309D}\shell |
3. Теперь необходимо создать новый ключ реестра в разделе «Shell». Нажмите правой кнопкой мыши на ключе «Shell» и выберите «Создать -> Раздел». Дайте ему какое-то оригинальное и неподражаемое имя, например «Menu1» (без кавычек).
4. Теперь выберите только что созданный раздел «Menu1». В правой части окна нам необходимо создать 4 строковых параметра:
MUIVerb
SubCommands
Icon
Position
Параметры Icon и Position Вы можете и не создавать (они опциональны), а вот MUIVerb и SubCommands — обязательны.
MUIVerb — это имя каскадного меню, которое будет отображаться в контекстном меню. Вы можете назвать его как угодно, например, «Приложения», «Браузеры» и т.д.
SubCommands содержит список команд, разделенных точкой с запятой (;). Эти команды будут показаны в каскадном меню. Вы не можете напрямую добавить ярлык приложения. Сначала в этом списке Вам нужно дать команде имя, а после этого зарегистрировать ее согласно инструкции во 2 Части статьи.
5. Давайте проясним насчет строкового параметра «SubCommands».
Предположим, что Вы уже создали каскадное меню «Apps» (переводчику неохота самому делать скрины, поэтому он не перевел это слово), как это описано в пункте 3, и теперь Вы хотите добавить в него ярлыки Notepad (блокнота) и Calculator (калькулятора). В таком случае Вам нужно задать такое значение параметру «SubCommands»:
notepad;calc |
Вы можете использовать и команды «Блокнот» и «Калькулятор», но в данном случае нужно будет использовать их во 2 части этой инструкции.
6. Параметр Icon используется для отображения иконки. В нашем примере его значение explorer.exe, поэтому у каскадного меню «Browsers» значок так горячо всеми любимого браузера.
7. Параметр «Position» используется для определения позиции каскадного меню в контекстном. По умолчанию это середина контекстного меню, но Вы можете выбрать значения Top (сверху) или Bottom (снизу).
8. Вы можете создать более одного меню, снова пройдя по пунктам 3 и 4.
Как только Вы добавите ярлыки программ в какскадные меню, Вам необходимо будет их зарегистрировать следующим образом:
1. Перейдите в следующий раздел:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\CommandStore\Shell |
2. В этом разделе нам нужно создать новые ключи для каждой из команд, указанных ранее в строковом параметре SubCommands.
В нашем примере мы использовали 2 команды: notepad и calc, поэтому нам нужно создать два ключа в разделе «CommandStore\Shell» с такими же именами.
3. После создания ключа выберите его и в правой части окна редактора реестра задайте параметру Default имя, которые Вы хотите видеть в каскадном меню. Например, введите сюда Notepad или Calculator или любую другую строку.
4. Если Вы также хотите добавить ярлыку иконку, создайте новый строковой параметр с именем icon и установите его значением путь к EXE файлу приложения или любой другой иконке. Например, чтобы показать иконку «блокнота», Вы должны задать параметру Icon значение notepad.exe
5. И теперь последний шаг! В каждом из только что созданных ключей создайте новый ключ и назовите его command.
Выберите его и в правой части окна установите значением Default путь к EXE-файлу необходимой программы. Например, если ярлык должен открывать «блокнот», то для Command должно быть установлено значение notepad.exe
Блокнот является родным Windows-приложением, поэтому Вы можете не указывать полный путь к нему, но если Вы хотите запускать стороннюю программу, то необходимо указать полный путь к ее EXE-файлу.
Автор в оригинальном тексте приводит уже готовые reg-файлы, поэтому можно взять их за основу и сделать это все намного быстрее.
Контекстное меню рабочего стола:
Windows Registry Editor Version 5.00 [HKEY_CLASSES_ROOT\DesktopBackground\Shell\Menu1] «MUIVerb»=«Apps» «SubCommands»=«notepad;calc» «icon»=«explorer.exe» [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\CommandStore\shell\notepad] @=«Notepad» «icon»=«notepad.exe» [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\CommandStore\shell\notepad\command] @=«notepad.exe» [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\CommandStore\shell\calc] @=«Calculator» «icon»=«calc.exe» [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\CommandStore\shell\calc\command] @=«calc.exe» |
Контекстное меню «Мой компьютер»:
Windows Registry Editor Version 5.00 [HKEY_CLASSES_ROOT\CLSID\{20D04FE0-3AEA-1069-A2D8-08002B30309D}\shell\Menu1] «MUIVerb»=«Apps» «SubCommands»=«notepad;calc» «icon»=«explorer.exe» [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\CommandStore\shell\notepad] @=«Notepad» «icon»=«notepad.exe» [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\CommandStore\shell\notepad\command] @=«notepad.exe» [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\CommandStore\shell\calc] @=«Calculator» «icon»=«calc.exe» [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\CommandStore\shell\calc\command] @=«calc.exe» |
Если Вы хотите удалить созданное каскадное меню, просто удалите ключи, созданные в пункте 3 первой части и пункте 2 второй части статьи.
Чтобы было наглядней о чем разговор идет, опишу как происходит процесс делегирования. Делегирование — это то каким образом пространство имен в DNS делится на зоны. Зона — это обособленная ветвь пространства DNS имен которая располагается на своих авторитарных DNS серверах. В зону может входить любое количество доменов нижележащего уровня — до тех пор пока они все расположены на одних и тех же авторитарных серверах, зона у них одна и та же.
Делегирование из родительской зоны происходит путем создания NS записей. В дочерней (делегированной) зоне создается полное описание зоны начиная с SOA записи. Вот, например, когда регистрируется домен второго уровня через регистратора nic.ru, то там при регистрации просят указать имена и адреса минимум двух DNS серверов которые будут считаться авторитарными для данной ветви пространства DNS имен. Для проведения делегирования не обязательно иметь под зону именно два DNS сервера — просто у nic.ru такая политика для того чтобы заставить клиентов обеспечить надежность системы. Вот эти два сервера становятся NS записями в домене ru.
Пример. Скажем, нами регистрируется домен второго уровня под названием net.ru. Авторитарными для него будут DNS сервера ns.net.ru (IP 1.2.3.4) и ns2.dnshosting.com (IP 5.6.7.9). В записях DNS серверов отвечающих за зону ru. (которыми управляет организация nic.ru) вносится такая информация:
$TTL 300 ru. IN SOA ns.ripn.net. hostmaster.ripn.net. ( 4014396 ;serial 7200 ;refresh 900 ;retry 2592000 ;expire 3600 ;neg. ttl ) NS sunic.sunet.se. NS e.dns.ripn.net. NS ns.ripn.net. NS ns5.msk-ix.net. ; это добавили net.ru. NS ns.net.ru. net.ru. NS ns2.dnshosting.com. ns.net.ru. A 1.2.3.4 |
Запись «ns.net.ru. A 1.2.3.4» называют еще «glue record», она нужна в случаях, когда имя NS сервера располагается внутри делегированной зоны. Это вспомогательная запись которую обязательно указывать в таких случаях. Без нее возникла бы ситуация, когда для того чтобы узнать IP сервера ns.net.ru надо обратиться к нему по IP (замкнутый круг). Так как второй NS расположен в чужой зоне, то для него не указываем glue record.
В свою очередь на сервере ns.net.ru который является мастером для зоны net.ru создается полная SOA запись как и полагается:
$TTL 300 net.ru. IN SOA ns.net.ru. hostmaster.net.ru. ( 2009012500 ;serial 7200 ;refresh 900 ;retry 2592000 ;expire 3600 ;neg. ttl ) NS ns.net.ru. NS ns2.dnshosting.com. MX 10 mail.net.ru. ns.net.ru. A 1.2.3.4 www.net.ru. A 9.8.7.6 ftp.net.ru. A 10.11.12.13 mail.net.ru. A 11.12.13.14 |
На slave сервере ns2.dnshosting.com в ручную записи не создаются, но он настраивается так чтобы периодически запрашивать мастер ns.net.ru и перекачивать с него всю информацию о записях в домене, а мастер ns.net.ru настраивается так чтобы отдавать все записи о зоне при запросах с подчиненного.
Точно по такой же схеме происходит делегирование доменов третьего, четвертого да любого уровня. Делегировать можно даже одно единственное хост имя!
Например случай с делегированием домена третьего уровня. Выглядеть это будет так — в записях зоны net.ru добавляется информация с NS записями о субдомене home.net.ru (допустим, будет только один авторитарный DNS сервер для этого субдомена ns.home.net.ru IP 7.7.7.7)
$TTL 300 net.ru. IN SOA ns.net.ru. hostmaster.net.ru. ( 2009012500 ;serial 7200 ;refresh 900 ;retry 2592000 ;expire 3600 ;neg. ttl ) NS ns.net.ru. NS ns2.dnshosting.com. MX 10 mail.net.ru. ns.net.ru. A 1.2.3.4 www.net.ru. A 9.8.7.6 ftp.net.ru. A 10.11.12.13 mail.net.ru. A 11.12.13.14 ;это добавили home.net.ru. NS ns.home.net.ru. ns.home.net.ru. A 7.7.7.7 |
Ну и соответственно на DNS сервере ns.home.net.ru создается зона с новой SOA записью:
$TTL 300 home.net.ru. IN SOA ns.home.net.ru. adminzoni.mail.ru. ( 2009012501 ;serial 7200 ;refresh 900 ;retry 2592000 ;expire 3600 ;neg. ttl ) NS ns.home.net.ru. ns.home.net.ru. A 7.7.7.7 home.net.ru. A 7.7.7.8 www.home.net.ru. A 7.7.7.8 proxy.home.net.ru. A 7.7.7.9 |
Был приведен синтаксис зоны как это принято в BIND и NSD. Для djbdns то, что написано выше будет выглядеть так:
Zhome.net.ru:ns.home.net.ru.:adminzoni.mail.ru.: \ 2009012501:7200:900:2592000:3600:300 &home.net.ru:7.7.7.7:ns.home.net.ru +home.net.ru:7.7.7.8:300 +www.home.net.ru:7.7.7.8:300 +proxy.home.net.ru:7.7.7.9:300 |
До кучи, напишу заодно еще и про реверс зоны и их делегирование.
Система DNS позволяет производить обратные разрешения из IP адресов в DNS имена. Для этого в дереве имен есть специальный служебный домен под именем in-addr.arpa. Этот домен имеет 256 субдоменов, каждый из субдомменов может иметь 256 своих субдоменов, у которых могут быть 256 своих субдоменов, в которых уже будет по 256 имен. Таким образом получается структура вида a.b.c.d.in-addr.arpa. где а,b,c,d это 0-255. На эту часть DNS имен распространяются те же правила, что и на обычные имена, вот только владельцем какого-либо субдомена может стать лишь организация получившая контроль за соответствующим блоком IP адресов — например провайдер, когда покупает для своих нужд у RIPE диапазоны IP адресов. Например, если провайдер купил себе префикс с адресами 123.44.55.0/24 (256 адресов), то он может получить от RIPE (регионального регистратора) и реверс зону в которой начнет создавать PTR записи по просьбе клиентов или для своих нужд:
$TTL 300 55.44.123.in-addr.arpa. IN SOA ns.net.ru. admin.net.ru. ( 2009012500 ;serial 7200 ;refresh 900 ;retry 2592000 ;expire 3600 ;neg. ttl ) NS ns.net.ru. NS ns2.dnshosting.com. 1.55.44.123.in-addr.arpa. PTR hostname.net.ru. 2.55.44.123.in-addr.arpa. PTR imja.net.ru. 254.55.44.123.in-addr.arpa. PTR esheodnoija.net.ru. |
Тут все просто и красиво потому, что в этом примере деление на DNS зону и IP субнет произошло по границе третьего и четвертого байта в IP адресе, а как делегировать половину субнета или только пару IP адресов из него? Скажем, клиент купил себе 8 «белых» IP адресов и захотел получить контроль над назначением реверс имен для них?
В таком случае можно сделать делегирование таким образом — в родительской зоне создаются CNAME записи на подставной домен, а он уже делегируется клиенту:
$TTL 300 55.44.123.in-addr.arpa. IN SOA ns.net.ru. admin.net.ru. ( 2009012500 ;serial 7200 ;refresh 900 ;retry 2592000 ;expire 3600 ;neg. ttl ) NS ns.net.ru. NS ns2.dnshosting.com. 1.55.44.123.in-addr.arpa. PTR hostname.net.ru. 2.55.44.123.in-addr.arpa. PTR imja.net.ru. 254.55.44.123.in-addr.arpa. PTR esheodnoija.net.ru. ;создаем подставные записи 7.55.44.123.in-addr.arpa. CNAME 7.klient.55.44.123.in-addr.arpa. 8.55.44.123.in-addr.arpa. CNAME 8.klient.55.44.123.in-addr.arpa. 9.55.44.123.in-addr.arpa. CNAME 9.klient.55.44.123.in-addr.arpa. 10.55.44.123.in-addr.arpa. CNAME 10.klient.55.44.123.in-addr.arpa. 11.55.44.123.in-addr.arpa. CNAME 11.klient.55.44.123.in-addr.arpa. 12.55.44.123.in-addr.arpa. CNAME 12.klient.55.44.123.in-addr.arpa. 13.55.44.123.in-addr.arpa. CNAME 13.klient.55.44.123.in-addr.arpa. 14.55.44.123.in-addr.arpa. CNAME 14.klient.55.44.123.in-addr.arpa. ;делегируем клиенту klient.55.44.123.in-addr.arpa. NS ns1.klient.ru. klient.55.44.123.in-addr.arpa. NS ns2.hosting.com. |
Клиент принимает у себя:
$TTL 300 klient.55.44.123.in-addr.arpa. IN SOA ns.klient.ru. admin.klient.ru. ( 2009012502 ;serial 7200 ;refresh 900 ;retry 2592000 ;expire 3600 ;neg. ttl ) NS ns.klient.ru. NS ns2.hosting.com. 7.klient.55.44.123.in-addr.arpa. PTR host1.klient.ru. 8.klient.55.44.123.in-addr.arpa. PTR host2.klient.ru. 9.klient.55.44.123.in-addr.arpa. PTR host3.klient.ru. 10.klient.55.44.123.in-addr.arpa. PTR host4.klient.ru. 11.klient.55.44.123.in-addr.arpa. PTR host5.klient.ru. 12.klient.55.44.123.in-addr.arpa. PTR host6.klient.ru. 13.klient.55.44.123.in-addr.arpa. PTR host7.klient.ru. 14.klient.55.44.123.in-addr.arpa. PTR host8.klient.ru. ... |
Да, еще одна штука вспомнилась.
Я когда работал в провайдере, так все хотел приколоться и сделать себе почтовый адрес вида terminus@1.2.3.4.in-addr.arpa, но не успел — все лень было, а потом уволился и сейчас своих реверс зон нет нигде.
Между прочим, нету никакаих объективных причин почему бы такое не работало — DNS должен будет корректно отвечать на запросы о MX записях для домена 1.2.3.4.in-addr.arpa так же как и для обычных доменов. Если есть в наличии SMTP сервер «для поиграться» + желание приколоться, то можно прописать в PTR зоне MX запись, на почтовом сервере на который указывают MX запись прописать домен, и проверить как оно будет (99% что должно работать).
Источник
Под ссылками в Windows я понимаются ссылки в NTFS. В FAT механизмов ссылок предусмотрено не было.
Ядро Windows поддерживает следующие виды ссылок:
Если вы никогда не имели дела с символическими и жёсткими ссылками, но хотели бы узнать о них, советую прочитать отрывок из документации файлового менеджера FAR:
Жесткие и символические связи
На разделах NTFS также можно создавать жесткие (HardLink) связи для файлов и символические (SymLink) для папок с помощью команды Alt-F6.
Жесткие связи применяются для файлов. Символические связи — для папок и дисков.
Жесткие связи
Жесткая связь (HardLink) — это просто еще одна запись в папке для данного файла.
Когда создается жесткая связь, сам файл не копируется физически, а только появляется под еще одним именем или в еще одном месте, а его старые имя и местонахождение остаются нетронутыми. С этого момента жесткая связь неотличима от первоначальной записи в папке. Единственное отличие — то, что для жесткой связи не создается короткое имя файла, поэтому из программ ДОС она не видна.
Когда меняется размер или дата файла, все соответствующие записи в папках обновляются автоматически. При удалении файла он не удаляется физически до тех пор, пока все жесткие связи, указывающие на него, не будут удалены. Порядок их удаления значения не имеет. При удалении жесткой связи в корзину количество связей у файла сохраняется.
FAR умеет создавать жесткие связи, отображать количество жестких связей для каждого файла в отдельной колонке (по умолчанию это последняя колонка в 9-м режиме панелей), а также сортировать файлы по количеству жестких связей.
Жесткие связи поддерживаются в NTFS, начиная с NT 4.0. Создавать жесткие связи можно только на том же диске, на котором расположен исходный файл.
Символические связи
NTFS начиная с версии 5.0 (Windows 2000/XP) поддерживает символические связи (SymLink). Символические связи папок в Windows 2000/XP известны как «directory junctions» — технология, позволяющая отображать любые локальные папки на любые другие локальные папки. Например, если папка D:\SYMLINK указывает на C:\WINNT\SYSTEM32 в качестве своей цели, то программа, обращающаяся к D:\SYMLINK\DRIVERS, будет на самом деле обращаться к C:\WINNT\SYSTEM32\DRIVERS.
FAR умеет создавать символические связи только на локальных дисках, файловая система которых поддерживает эту возможность (Windows 2000/XP/NTFS 5.0). В отличие от жестких связей, символические связи не обязательно должны указывать на тот же диск.
Напрямую делать символические связи на папки CD-ROM нельзя, но можно это ограничение обойти, смонтировав CD-ROM диск на папку NTFS-раздела.
Там говорится только о Hard Links и Junction Points, но этого вполне достаточно. Symbolic Links действуют так же, как и Junction Points, с той разницей, что могут указывать на файлы (и реализованы в Windows по-другому).
Hard Links можно создавать только на файлы, Junction Points — только на директории, Symbolic Links — на файлы и директории. В дальнейшем под «жёсткими ссылками» подразумеваются Hard Links, под «символьными» — Junction Points и Symbolic Links.
Жёсткие ссылки действительны в пределах одного раздела, символьные — могут пересекать границы разделов. В связи с этим символьные ссылки могут поломаться, если структуру разделов поменять.
Не со всем, что поддерживается ядром, умеет нормально работать эксплорер. Будьте осторожны при использовании Junction Points в версиях Windows до Vista. При удалении Junction Point эксплорер может залезть внутрь директории, на которую ссылается Junction Point и поудалять там всё, а затем удалить Junction Point, хотя должен лишь удалить ссылку. Наверняка могут возникнуть проблемы и при перемещении или копировании Junction Point’ов.
Мне неизвестно, нормально ли в версиях Windows до Vista относятся к Junction Points стандартные утилиты типа rmdir.
Отмечу англоязычную статью, в которой описаны нюансы использования ссылок и некоторые программы, позволяющие с ними работать. Статья устаревшая, так что в ней говорится только о Hard Links и Junction Points (причём на последние в статье нередко ссылаются, как на symbolic links…).
Хорошее описание всех видов ссылок есть ещё в справке по NTFS Links (дополнение для Total Commander).
Теперь можно перейти к рассмотрению программ для работы со ссылками. Да-да, если вы не пользуетесь FAR, вам понадобятся отдельные программы. Все программы, перечисленные ниже, бесплатны.
В Windows Vista добавили команду
mklink |
для создания символьных и жёстких ссылок.
fsutil hardlink create ссылка файл |
Создаёт Hard Link на файл (источник).
linkd ссылка директория |
Создаёт Junction Point на директорию (источник). Утилита входит в Microsoft Windows Resources Kit.
NTFS Link интегрируется в Explorer и добавляет во всплывающее меню, появляюшееся после перетаскивания правой кнопкой мыши, пункты «Create junction point» и «Create hard link». Кроме того, она перехватывает вызовы Explorer’а, обеспечивая нормальное перемещение/копирование/удаление созданных ссылок.
NTFS Links (не путать с дополнением для Total Commander) — абсолютно аналогичная программа.
Я рекомендую: Link Shell Extension — аналогичная программа, обладающая расширенным функционалом и очень подробным описанием.
Страница программы. Плагин может запускаться как отдельная программа, вне Total Commander’а.
Консольный файловый менеджер FAR уже давно поддерживает Hard Links и Junction Points «из коробки». Для создания ссылки используйте сочетание клавиш Alt-F6.
Junction Link Magic — программа с графическим интерфейсом для создания, изменения и модификации Junction Points.
Junction лучше, чем
linkd |
, тем, что не нужно тащить весь Resource Kit.
Чтобы было наглядней о чем разговор идет, опишу как происходит процесс делегирования. Делегирование — это то каким образом пространство имен в DNS делится на зоны. Зона — это обособленная ветвь пространства DNS имен которая располагается на своих авторитарных DNS серверах. В зону может входить любое количество доменов нижележащего уровня — до тех пор пока они все расположены на одних и тех же авторитарных серверах, зона у них одна и та же.
Делегирование из родительской зоны происходит путем создания NS записей. В дочерней (делегированной) зоне создается полное описание зоны начиная с SOA записи. Вот, например, когда регистрируется домен второго уровня через регистратора nic.ru, то там при регистрации просят указать имена и адреса минимум двух DNS серверов которые будут считаться авторитарными для данной ветви пространства DNS имен. Для проведения делегирования не обязательно иметь под зону именно два DNS сервера — просто у nic.ru такая политика для того чтобы заставить клиентов обеспечить надежность системы. Вот эти два сервера становятся NS записями в домене ru.
Пример. Скажем, нами регистрируется домен второго уровня под названием net.ru. Авторитарными для него будут DNS сервера ns.net.ru (IP 1.2.3.4) и ns2.dnshosting.com (IP 5.6.7.9). В записях DNS серверов отвечающих за зону ru. (которыми управляет организация nic.ru) вносится такая информация:
$TTL 300 ru. IN SOA ns.ripn.net. hostmaster.ripn.net. ( 4014396 ;serial 7200 ;refresh 900 ;retry 2592000 ;expire 3600 ;neg. ttl ) NS sunic.sunet.se. NS e.dns.ripn.net. NS ns.ripn.net. NS ns5.msk-ix.net. ; это добавили net.ru. NS ns.net.ru. net.ru. NS ns2.dnshosting.com. ns.net.ru. A 1.2.3.4 |
Запись «ns.net.ru. A 1.2.3.4» называют еще «glue record», она нужна в случаях, когда имя NS сервера располагается внутри делегированной зоны. Это вспомогательная запись которую обязательно указывать в таких случаях. Без нее возникла бы ситуация, когда для того чтобы узнать IP сервера ns.net.ru надо обратиться к нему по IP (замкнутый круг). Так как второй NS расположен в чужой зоне, то для него не указываем glue record.
В свою очередь на сервере ns.net.ru который является мастером для зоны net.ru создается полная SOA запись как и полагается:
$TTL 300 net.ru. IN SOA ns.net.ru. hostmaster.net.ru. ( 2009012500 ;serial 7200 ;refresh 900 ;retry 2592000 ;expire 3600 ;neg. ttl ) NS ns.net.ru. NS ns2.dnshosting.com. MX 10 mail.net.ru. ns.net.ru. A 1.2.3.4 www.net.ru. A 9.8.7.6 ftp.net.ru. A 10.11.12.13 mail.net.ru. A 11.12.13.14 |
На slave сервере ns2.dnshosting.com в ручную записи не создаются, но он настраивается так чтобы периодически запрашивать мастер ns.net.ru и перекачивать с него всю информацию о записях в домене, а мастер ns.net.ru настраивается так чтобы отдавать все записи о зоне при запросах с подчиненного.
Точно по такой же схеме происходит делегирование доменов третьего, четвертого да любого уровня. Делегировать можно даже одно единственное хост имя!
Например случай с делегированием домена третьего уровня. Выглядеть это будет так — в записях зоны net.ru добавляется информация с NS записями о субдомене home.net.ru (допустим, будет только один авторитарный DNS сервер для этого субдомена ns.home.net.ru IP 7.7.7.7)
$TTL 300 net.ru. IN SOA ns.net.ru. hostmaster.net.ru. ( 2009012500 ;serial 7200 ;refresh 900 ;retry 2592000 ;expire 3600 ;neg. ttl ) NS ns.net.ru. NS ns2.dnshosting.com. MX 10 mail.net.ru. ns.net.ru. A 1.2.3.4 www.net.ru. A 9.8.7.6 ftp.net.ru. A 10.11.12.13 mail.net.ru. A 11.12.13.14 ;это добавили home.net.ru. NS ns.home.net.ru. ns.home.net.ru. A 7.7.7.7 |
Ну и соответственно на DNS сервере ns.home.net.ru создается зона с новой SOA записью:
$TTL 300 home.net.ru. IN SOA ns.home.net.ru. adminzoni.mail.ru. ( 2009012501 ;serial 7200 ;refresh 900 ;retry 2592000 ;expire 3600 ;neg. ttl ) NS ns.home.net.ru. ns.home.net.ru. A 7.7.7.7 home.net.ru. A 7.7.7.8 www.home.net.ru. A 7.7.7.8 proxy.home.net.ru. A 7.7.7.9 |
Был приведен синтаксис зоны как это принято в BIND и NSD. Для djbdns то, что написано выше будет выглядеть так:
Zhome.net.ru:ns.home.net.ru.:adminzoni.mail.ru.: \ 2009012501:7200:900:2592000:3600:300 &home.net.ru:7.7.7.7:ns.home.net.ru +home.net.ru:7.7.7.8:300 +www.home.net.ru:7.7.7.8:300 +proxy.home.net.ru:7.7.7.9:300 |
До кучи, напишу заодно еще и про реверс зоны и их делегирование.
Система DNS позволяет производить обратные разрешения из IP адресов в DNS имена. Для этого в дереве имен есть специальный служебный домен под именем in-addr.arpa. Этот домен имеет 256 субдоменов, каждый из субдомменов может иметь 256 своих субдоменов, у которых могут быть 256 своих субдоменов, в которых уже будет по 256 имен. Таким образом получается структура вида a.b.c.d.in-addr.arpa. где а,b,c,d это 0-255. На эту часть DNS имен распространяются те же правила, что и на обычные имена, вот только владельцем какого-либо субдомена может стать лишь организация получившая контроль за соответствующим блоком IP адресов — например провайдер, когда покупает для своих нужд у RIPE диапазоны IP адресов. Например, если провайдер купил себе префикс с адресами 123.44.55.0/24 (256 адресов), то он может получить от RIPE (регионального регистратора) и реверс зону в которой начнет создавать PTR записи по просьбе клиентов или для своих нужд:
$TTL 300 55.44.123.in-addr.arpa. IN SOA ns.net.ru. admin.net.ru. ( 2009012500 ;serial 7200 ;refresh 900 ;retry 2592000 ;expire 3600 ;neg. ttl ) NS ns.net.ru. NS ns2.dnshosting.com. 1.55.44.123.in-addr.arpa. PTR hostname.net.ru. 2.55.44.123.in-addr.arpa. PTR imja.net.ru. 254.55.44.123.in-addr.arpa. PTR esheodnoija.net.ru. |
Тут все просто и красиво потому, что в этом примере деление на DNS зону и IP субнет произошло по границе третьего и четвертого байта в IP адресе, а как делегировать половину субнета или только пару IP адресов из него? Скажем, клиент купил себе 8 «белых» IP адресов и захотел получить контроль над назначением реверс имен для них?
В таком случае можно сделать делегирование таким образом — в родительской зоне создаются CNAME записи на подставной домен, а он уже делегируется клиенту:
$TTL 300 55.44.123.in-addr.arpa. IN SOA ns.net.ru. admin.net.ru. ( 2009012500 ;serial 7200 ;refresh 900 ;retry 2592000 ;expire 3600 ;neg. ttl ) NS ns.net.ru. NS ns2.dnshosting.com. 1.55.44.123.in-addr.arpa. PTR hostname.net.ru. 2.55.44.123.in-addr.arpa. PTR imja.net.ru. 254.55.44.123.in-addr.arpa. PTR esheodnoija.net.ru. ;создаем подставные записи 7.55.44.123.in-addr.arpa. CNAME 7.klient.55.44.123.in-addr.arpa. 8.55.44.123.in-addr.arpa. CNAME 8.klient.55.44.123.in-addr.arpa. 9.55.44.123.in-addr.arpa. CNAME 9.klient.55.44.123.in-addr.arpa. 10.55.44.123.in-addr.arpa. CNAME 10.klient.55.44.123.in-addr.arpa. 11.55.44.123.in-addr.arpa. CNAME 11.klient.55.44.123.in-addr.arpa. 12.55.44.123.in-addr.arpa. CNAME 12.klient.55.44.123.in-addr.arpa. 13.55.44.123.in-addr.arpa. CNAME 13.klient.55.44.123.in-addr.arpa. 14.55.44.123.in-addr.arpa. CNAME 14.klient.55.44.123.in-addr.arpa. ;делегируем клиенту klient.55.44.123.in-addr.arpa. NS ns1.klient.ru. klient.55.44.123.in-addr.arpa. NS ns2.hosting.com. |
Клиент принимает у себя:
$TTL 300 klient.55.44.123.in-addr.arpa. IN SOA ns.klient.ru. admin.klient.ru. ( 2009012502 ;serial 7200 ;refresh 900 ;retry 2592000 ;expire 3600 ;neg. ttl ) NS ns.klient.ru. NS ns2.hosting.com. 7.klient.55.44.123.in-addr.arpa. PTR host1.klient.ru. 8.klient.55.44.123.in-addr.arpa. PTR host2.klient.ru. 9.klient.55.44.123.in-addr.arpa. PTR host3.klient.ru. 10.klient.55.44.123.in-addr.arpa. PTR host4.klient.ru. 11.klient.55.44.123.in-addr.arpa. PTR host5.klient.ru. 12.klient.55.44.123.in-addr.arpa. PTR host6.klient.ru. 13.klient.55.44.123.in-addr.arpa. PTR host7.klient.ru. 14.klient.55.44.123.in-addr.arpa. PTR host8.klient.ru. ... |
Да, еще одна штука вспомнилась.
Я когда работал в провайдере, так все хотел приколоться и сделать себе почтовый адрес вида terminus@1.2.3.4.in-addr.arpa, но не успел — все лень было, а потом уволился и сейчас своих реверс зон нет нигде.
Между прочим, нету никакаих объективных причин почему бы такое не работало — DNS должен будет корректно отвечать на запросы о MX записях для домена 1.2.3.4.in-addr.arpa так же как и для обычных доменов. Если есть в наличии SMTP сервер «для поиграться» + желание приколоться, то можно прописать в PTR зоне MX запись, на почтовом сервере на который указывают MX запись прописать домен, и проверить как оно будет (99% что должно работать).
У большинства MySQL серверов включено кэширование запросов. Один из наилучших способов улучшения производительности — просто предоставить кэширование самой базе данных. Когда какой-либо запрос повторяется много раз, его результат берется из кэша, что гораздо быстрее прямого обращения к базе данных.
Основная проблема в том, что многие просто используют запросы, которые не могут быть закэшированны:
// запрос не будет кэширован $r = mysql_query("SELECT username FROM user WHERE signup_date >= CURDATE()"); // а так будет! $today = DATE("Y-m-d"); $r = mysql_query("SELECT username FROM user WHERE signup_date >= '$today'"); |
Причина в том, что в первом запросе используется функция CURDATE(). Это относиться ко всем функциям, подобным NOW(), RAND() и другим, результат которых недетерминирован. Если результат функции может измениться, то MySQL не кэширует такой запрос. В данном примере это можно предотвратить вычислением даты до выполнения запроса.
Используя EXPLAIN, вы можете посмотреть, как именно MySQL выполняет ваш запрос. Это может помочь вам избавиться от слабых мест производительности и других проблем в вашем запросе или в структуре таблиц.
Результат EXPLAIN покажет вам, какие используются индексы, как выбираются и сортируются таблицы и т.д.
Возьмите ваш SELECT запрос (он может быть сложным, с объединениями) и добавьте в начало ключевое слово EXPLAIN. Для этого вы можете использовать phpmyadmin. В результате вы получите очень интересную таблицу. Для примера, пусть я забыл добавить индекс в таблицу, которая участвует в объединении:
После добавления индекса для поля group_id:
Теперь вместо 7883 строк, выбираются только 9 и 16 строк из двух таблиц. Перемножение всех чисел в столбце rows даст число прямо пропорциональное производительности запроса.
Иногда, обращаясь к таблице, вы точно знаете, что вам нужна только одна конкретная строка. Например, нужно получить одну уникальную строку или просто проверить существование записей, удовлетворяющих запросу WHERE.
В этом случае, добавление LIMIT 1 в ваш запрос будет оптимальнее. Таким образом, база данных остановит выборку записей, после нахождения первой же, вместо того, чтобы выбрать всю таблицу или индекс.
// есть пользователи в Alabama? // можно так: $r = mysql_query("SELECT * FROM user WHERE state = 'Alabama'"); IF (mysql_num_rows($r) > 0) { // ... } // но так лучше: $r = mysql_query("SELECT * FROM user WHERE state = 'Alabama' LIMIT 1"); IF (mysql_num_rows($r) > 0) { // ... } |
Индекс это не только основной или уникальный ключ. Это так же любые столбцы в таблице, которые вы используете для поиска и их можно проиндексировать.
Как вы можете заметить, это правило также применимо для части строк, например — «last_name LIKE ‘a%’». При поиске с начала строки, MySQL использует индекс этого столбца.
Вы так же должны понимать, что это не сработает для регулярных выражений. Например, когда вы ищите слово (т.е. «WHERE post_content LIKE ‘%apple%’»), то от обычного индекса не будет никакого толку. Лучше будет использовать полнотекстовый поиск или создать вашу собственную систему индексации.
Если ваше приложение содержит много объединений таблиц, вам необходимо проиндексировать в обеих таблицах поля, используемые для объединения. Это повлияет на то, как MySQL делает внутреннюю оптимизацию объединений.
Так же эти столбцы должны быть одного типа. Например, если вы объединяете столбец DECIMAL со столбцом INT из другой таблицы, MySQL не сможет использовать хотя бы один из индексов. Даже кодировки символов должны быть одного типа для строковых столбцов.
// выборки компаний в штате пользователя $r = mysql_query("SELECT company_name FROM users JOIN companies ON (users.state = companies.state) users.id = $user_id"); // обе колонки state должны быть проиндексированны // они обе должны иметь один тип данных и кодировку символов // а иначе MySQL сделает полную выборку из этих таблиц |
(Имеется в виду выборка единственной строки. Примечание переводчика)
Это одна из тех вещей, который выглядят очень хорошо на первый взгляд, но многие начинающие программисты попались на эту удочку. Вы даже не представляете, какое слабое место в производительности возникнет, если будете использовать это в запросах.
Если вам действительно нужен случайный порядок строк в запросе, то есть лучшие способы сделать это. Конечно, это приведет к дополнительному коду, но позволит избавиться от слабого места в производительности, которое будет сужаться экспоненциально при увеличении данных. Проблема в том, что MySQL будет выполнять RAND() (а это нагрузка на процессор) для каждой строки при сортировке, выдавая только одну строку.
Таким образом вы выберите случайный номер, который меньше количества строк и используете его для смещения в LIMIT.
Чем больше данных считывается из таблицы, тем медленнее запрос. Это увеличивает время работы с хранилищем данных. Также, когда сервер базы данных установлен отдельно от web-сервера, будет большая задержка при передаче данных по сети.
Прописывать, какие именно столбцы из запроса вам нужны — хорошая привычка.
// не очень хорошо: $r = mysql_query(«SELECT * FROM USER WHERE user_id = 1»); $d = mysql_fetch_assoc($r); echo «Welcome {$d['username']}»; // лучше: $r = mysql_query(«SELECT username FROM USER WHERE user_id = 1»); $d = mysql_fetch_assoc($r); echo «Welcome {$d['username']}»; // разница более значительна при большем наборе данных. |
В каждой таблице нужно поле id, которое будет PRIMARY KEY, AUTO_INCREMENT, а так же иметь тип INT. Так же неплохо, чтобы оно было UNSIGNED, т.к. вряд ли у идентификатора будут отрицательные значения.
Даже если в вашей таблице пользователей есть уникальное поле username, не делаете его основным ключом. Использование поля VARCHAR, как основного ключа, очень медлительно. Да и структура вашего кода, относящаяся к пользователям, будет гораздо лучше, если у каждого пользователя будет свой внутренний идентификатор.
Есть так же и внутренние операции MySQL, использующие первичный ключ. И это становиться очень важно для более сложных конфигураций базы данных (кластеры, распараллеливание и т.д.)
Исключение из этого правила составляют «таблицы ассоциаций», используемые для связи «многие-ко-многим» между 2 таблицами. Например, таблица «posts_tags», содержит 2 поля: post_id, tag_id, который используется для объединения между двумя таблицами «Posts» и «Tags». Эта таблица будет иметь первичный ключ составленный из 2 полей.
ENUM — очень быстрый и компактный тип поля. Значения в нем храниться так же, как TINYINT, но отображаются как в строковом поле. Это делает его незаменимым в некоторых случаях.
Если у вас есть поле, в котором будет вполне определенный набор значений, используйте ENUM вместо VARCHAR. Например, если есть поле «status», его значения могут быть «active», «inactive», «pending», «expired» и т.д.
Можно даже получить от MySQL «совет» о том, как перестроить таблицу. Если у вас есть поле VARCHAR, MySQL может предложить заменить его на ENUM. Для этого используется PROCEDURE ANALYSE(), описанная ниже.
PROCEDURE ANALYSE() анализирует структуру вашей таблицы и данные в ней, и выдает возможные советы по оптимизации. Это возможно только при наличии реальных данных в таблице, т.к. анализ делается в основном на их основе.
Например, если вы создали первичный ключ типа INT, а записей не очень много, MySQL может предложить заменить его на MEDIUMINT. Или, если используется VARCHAR в котором есть несколько уникальных значений, будет предложен ENUM.
В phpmyadmin в структуре таблице есть ссылка «Анализ структуры таблицы», результат которой может быть, например, следующим:
Если есть особые причины использовать NULL — используйте его. Но перед этим спросите себя — есть ли разница между пустой строкой и NULL (для INT — 0 или NULL). Если таких причин нет, используйте NOT NULL.
NULL занимает больше места и, к тому же, усложняет сравнения с таким полем. Избегайте его, если это возможно. Тем не менее, бывают веские причины использовать NULL, это не всегда плохо.
Из документации MySQL:
«Столбцы NULL занимают больше места в записи, из-за необходимости отмечать, что это NULL значение. Для таблиц MyISAM, каждое поле с NULL занимает 1 дополнительный бит, который округляется до ближайшего байта».
Если есть особые причины использовать NULL — используйте его. Но перед этим спросите себя — есть ли разница между пустой строкой и NULL (для INT — 0 или NULL). Если таких причин нет, используйте NOT NULL.
NULL занимает больше места и, к тому же, усложняет сравнения с таким полем. Избегайте его, если это возможно. Тем не менее, бывают веские причины использовать NULL, это не всегда плохо.
Из документации MySQL:
«Столбцы NULL занимают больше места в записи, из-за необходимости отмечать, что это NULL значение. Для таблиц MyISAM, каждое поле с NULL занимает 1 дополнительный бит, который округляется до ближайшего байта».
Есть множество преимуществ в использовании prepared statements, как для безопасности, так и для улучшения производительности. Prepared statements фильтруют значения данных, добавляемых в запрос, что защищает запросы от SQL инъекций. Конечно, вы можете фильтровать переменные вручную, но тут может сказаться человеческая забывчивость и невнимательность. Конечно, это не столь важно при использовании какого-либо фреймворка или ORM.
Поскольку статья посвящена оптимизации, отмечу также выгоды для нее. Они проявляются, когда запрос выполняется много раз в приложении. Вы можете использовать для prepared statement разные значения, но MySQL будет разбирать запрос только один раз.
Кроме того, последние версии MySQL компилируют prepared statements в бинарную форму, что позволяет повысить эффективность.
Раньше многие программисты избегали prepared statements по одной единственной причине — они не кэшировались MySQL, но с версии 5.1 это не так.
Посмотрите mysqli extension для использования prepared statements или воспользуйтесь абстракцией базы данных, например, PDO.
// создаем a prepared statement IF ($stmt = $mysqli->PREPARE("SELECT username FROM user WHERE state=?")) { // привязываем значения $stmt->bind_param("s", $state); // выполняем $stmt->EXECUTE(); // привязываем результат $stmt->bind_result($username); // получаем данные $stmt->fetch(); printf("%s is from %s\n", $username, $state); $stmt->close(); } |
Обычно, делая запрос, скрипт останавливается и ждет результата его выполнения. Вы можете изменить это, используя небуферизованные запросы.
Хорошее описание есть в документации функции mysql_unbuffered_query():
«mysql_unbuffered_query() отправляет SQL-запрос в MySQL, не извлекая и не автоматически буферизуя результирующие ряды, как это делает mysql_query(). С одной стороны, это сохраняет значительное количество памяти для SQL-запросов, дающих большие результирующие наборы. С другой стороны, вы можете начать работу с результирующим набором срезу после получения первого ряда: вам не нужно ожидать выполнения полного SQL-запроса»
Однако есть определенные ограничения. Вам придется считывать все записи или вызывать mysql_free_result() прежде, чем вы сможете выполнить другой запрос. Так же вы не можете использовать mysql_num_rows() или mysql_data_seek() для результата функции.
Многие программисты хранят IP адреса в поле типа VARCHAR(15), не зная что можно хранить его в целочисленном виде. INT занимает 4 байта и имеет фиксированный размер поля.
Убедитесь, что используете UNSIGNED INT, т.к. IP можно записать как 32 битное беззнаковое число.
Используйте в запросе INET_ATON() для конвертирования IP адреса в число, и INET_NTOA() для обратного преобразования. Такие же, такие функции есть и в PHP — ip2long() и long2ip() (в php эти функции могут вернуть и отрицательные значения. замечание от хабраюзера The_Lion).
$r = "UPDATE users SET ip = INET_ATON('{$_SERVER['REMOTE_ADDR']}') WHERE user_id = $user_id"; |
Если каждая колонка в таблице имеет фиксированный размер, то такая таблица называется «статичной» или «фиксированного размера». Пример колонок не фиксированной длины: VARCHAR, TEXT, BLOB. Если включить в таблицу такое поле, она перестанет быть фиксированной и будет обрабатываться MySQL по-другому.
Использование таких таблицы увеличит эффективность, т.к. MySQL может просматривать записи в них быстрее. Когда надо выбрать нужную строку таблицы, MySQL может очень быстро вычислить ее позицию. Если размер записи не фиксирован, ее поиск происходит по индексу.
Так же эти таблицы проще кэшировать и восстанавливать после падения базы. Например, если перевести VARCHAR(20) в CHAR(20), запись будет занимать 20 байтов, вне зависимости от ее реального содержания.
Используя метод «вертикального разделения», вы можете вынести столбцы с переменной длиной строки в отдельную таблицу.
Вертикальное разделение — означает разделение таблицы по столбцам для увеличения производительности.
Пример 1. Если в таблице пользователей хранятся адреса, то не факт что они будут нужны вам очень часто. Вы можете разбить таблицу и хранить адреса в отдельной таблице. Таким образом, таблица пользователей сократиться в размере. Производительность возрастет.
Пример 2. У вас есть поле «last_login» в таблице. Оно обновляется при каждом входе пользователя на сайт. Но все изменения в таблице очищают ее кэш. Храня это поле в другой таблице, вы сведете изменения в таблице пользователей к минимуму.
Но если вы будете постоянно использовать объединение этих таблиц, это приведет к ухудшению производительности.
Если вам необходимо сделать большой запрос на удаление или вставку данных, надо быть осторожным, чтобы не нарушить работу приложения. Выполнение большого запроса может заблокировать таблицу и привести к неправильной работе всего приложения.
Apache может выполнять несколько параллельных процессов одновременно. Поэтому он работает более эффективно, если скрипты выполняются как можно быстрее.
Если вы блокируете таблицы на долгий срок (например, на 30 секунд или дольше), то при большой посещаемости сайта, может возникнуть большая очередь процессов и запросов, что может привести к медленной работе сайта или даже к падению сервера.
Если у вас есть такие запросы, используйте LIMIT, чтобы выполнять их небольшими сериями.
while (1) { mysql_query("DELETE FROM logs WHERE log_date <= '2009-10-01' LIMIT 10000"); IF (mysql_affected_rows() == 0) { // удалили break; } // небольшая пауза usleep(50000); } |
Для базы данных работа с жестким диском, возможно, является самым слабым местом. Маленькие и компактные записи обычно лучше с точки зрения производительности, т.к. уменьшают работу с диском.
В документации к MySQL есть список требований к хранилищам данных для всех типов данных.
Если ваша таблица будет хранить мало строк, то не имеет смысла делать основной ключ типом INT, возможно лучше будет сделать его MEDIUMINT, SMALLINT или даже TINYINT. Если вам не нужно хранить время, используйте DATE вместо DATETIME.
Однако будьте осторожны, что бы не вышло как с Slashdot.
Два основных типа таблиц — MyISAM и InnoDB, у каждого есть свои плюсы и минусы.
MyISAM хорошо считывает из таблиц большое количество данных, но он плох для записи. Даже если вы изменяете всего одну строку, блокируется вся таблица, и ни один процесс не может ничего из нее прочитать. MyISAM очень быстро выполняет запросы типа SELECT COUNT(*).
У InnoDB более сложный механизм хранения данных, и он может быть медленнее, чем MyISAM, для маленьких приложений. Но он поддерживает блокировку строк, что более эффективно при масштабировании. Так же поддерживаются некоторые дополнительные функции, такие операции как транзакции.
Подробнее:MyISAM Storage EngineInnoDB Storage Engine
Используя ORM, можно получить определенную оптимизацию работы. Все, что можно сделать с помощью ORM, можно сделать и вручную. Но это требует дополнительной работы и более высокого уровня знаний.
ORM замечателен для «ленивой» загрузки данных. Это означает выборку данных по мере необходимости. Но необходимо быть осторожным, т.к это может привести к появлению множества маленьких запросов, что приведет к снижению производительности.
ORM также может объединять несколько запросов в пакеты, вместо отправки каждого отдельно.
Моя любимая ORM для PHP — Doctrine. Я уже писал статью об установке Doctrine в CodeIgniter.
Постоянные соединения предназначены для уменьшения расходов на установление связи с MySQL. Когда соединение создается, оно остается открытым после завершения работы скрипта. В следующий раз, этот скрипт воспользуется этим же соединением.mysql_pconnect() в PHPНо это звучит хорошо только в теории. Из моего личного опыта (и опыта других), использование этой возможности не оправдывается. У вас будут серьезные проблемы с ограничением по числу подключений, памятью и так далее.
Apache создает много параллельных потоков. Это основная причина, почему постоянные соединения не работаю так хорошо, как бы хотелось. Перед использованием mysql_pconnect() посоветуйтесь с вашим сисадмином.
Тут приведены некоторые полезные хитрости, направленные на более удобное использование командной строки. Все мы не хотим повторно набирать какую-то длинную команду и ищем ее в истории. Тут — пара трюков от том, как можно энто самое удобство малость повысить.
Многие пользуются стандартными гномовским или кдешным эмуляторами терминала. У них есть возможность открывать в одном окне несколько оболочек — каждую в отдельной вкладке.
bash по умолчанию пишет в историю набранные за сеанс команды только при своем закрытии (перед самоликвидацией). Поэтому при открытии нового терминала в другой вкладке вы не увидите только что набранные команды из первой вкладки — они еще не записаны в хистори.
К тому же закрыв первый терминал, а потом второй вы не найдете в истории команд набранных в первом терминале. Потому что по умолчанию bash не дописывает файл .history, а переписывает.
Исправить ситуацию можно, дописав в конфигурационный файл ~/.bashrc пару строк
shopt -s histappend PROMPT_COMMAND='history -a' |
Теперь каждая введенная вами команда будет писаться в историю сразу же. Не бойтесь — дырку на жестком месте такая конфигурация не протрет. Не так уж часто вы команды в баше набираете. 🙂 Да и слава богу кеширование дисков пока еще рулит.
Если дописать такую строчку
shopt -s cdspell |
то bash будет пытаться исправлять допущенные вами опечатки (пропуски и перестановки символов, например /ect/init.d вместо /etc/init.d) в пути у команды cd. Не бойтесь, у rm такая фича работать уже не будет. Только у cd.
Пишем в ~/.bashrc
export HISTCONTROL="ignoredups" |
А если вы не хотите, чтобы в историю попадали вызовы каких-то «неинформативных» команд, то их логирование можно запретить:
export HISTIGNORE="&:ls:[bf]g:exit" |
После этой команды в хистори не будут писаться команды &, ls, bg, fg, exit. Можно дописать и свои, через двоеточие, можно использовать шаблоны.
Еще команда в конфигурационный файл
shopt -s cmdhist |
Иногда команды бывают большими и сложными, и чтобы заново ее не писать и не искать по истории 100 раз нажимая «вверх», можно воспользоваться поиском.
Если вы помните кусочек команды которую хотите найти, то можно просто нажать в bash’e комбинацию Ctrl + R и набрать этот кусочек. bash вам покажет последнюю команду с такой подстрокой. Можно продолжать нажимать Ctrl + R и bash будет выдавать более старые подходящие команды, подходящие под искомую строку.
Когда мы работаем в какой-то директории, и нам нужно «выбраться» в другую директорию, что-то там поделать и вернуться назад, можно воспользоваться «cd -«, например
[toor@localhost html]$ cd /var/www/html [toor@localhost html]$ cd /etc/ [toor@localhost etc]$ vi my.cnf [toor@localhost etc]$ cd - /var/www/html [toor@localhost html]$ |
Эта команда вернет нас в директорию где мы были раньше.
По умолчанию утилита history, не сохраняет в .bash_history время исполнения каждой команды.
В баше трейтьей версии сделать это можно и весьма просто. Если объявить глобальную переменную HISTTIMEFORMAT с форматом выводимых данных, то утилита history будет сохранять и выводить эту дату.
Итак, пишем в ~/.bashrc строчку
export HISTTIMEFORMAT='%h %d %H:%M:%S ' |
После этого в .bash_history перед каждой командой появится коментарий с цифрой — временем выполнения этой команды в формате timestamp:
#1260787129 htop #1260802594 export HISTTIMEFORMAT='%h %d %H:%M:%S ' #1260802598 history | grep squid #1260802658 mc #1260802777 chown -R svn:svn svn |
А командочка history будет выдавать историю данных с датой в формате, который мы переменной задали (в похожем формате выдают дату и время утилита ls):
995 Dec 14 13:38:49 htop 996 Dec 14 17:56:34 export HISTTIMEFORMAT='%h %d %H:%M:%S ' 997 Dec 14 17:56:38 history | grep squid 998 Dec 14 17:57:38 mc 999 Dec 14 17:59:37 chown -R svn:svn svn |
Но можно сделать и по ГОСТУ, в приятном русскому глазу виде «ДД.ММ.ГГГГ»
export HISTTIMEFORMAT='%d.%m.%Y %H:%M:%S ' |
А можно и в формате ISO: «YYYY-MM-DD»
export HISTTIMEFORMAT='%Y-%m-%d %H:%M:%S ' |
На днях я столкнулся с тем, что многие разработчики не знают в чём отличие типов данных DATETIME и TIMESTAMP в MySQLе, а так же как хранить дату и время, если необходимо учитывать разные часовые пояса для разных пользователей веб-приложения. Поэтому хочу дать ниже разъяснения с пояснениями.
DATETIME
Хранит время в виде целого числа вида YYYYMMDDHHMMSS, используя для этого 8 байтов. Это время не зависит от временной зоны. Оно всегда отображается при выборке точно так же, как было сохранено, независимо от того какой часовой пояс установлен в MySQL. Даю пример:
mysql> CREATE TABLE `dt1` ( col datetime NOT NULL ); mysql> SET @@SESSION.time_zone='+00:00'; mysql> SELECT now(); +---------------------+ | now() | +---------------------+ | 2009-06-04 18:13:56 | +---------------------+ mysql> INSERT INTO dt1 VALUES(now()); mysql> SET @@SESSION.time_zone='+01:00'; mysql> SELECT now(); +---------------------+ | now() | +---------------------+ | 2009-06-04 19:14:20 | +---------------------+ mysql> INSERT INTO dt1 VALUES(now()); mysql> SET @@SESSION.time_zone='+00:00'; mysql> SELECT * FROM dt1; +---------------------+ | col | +---------------------+ | 2009-06-04 18:14:10 | | 2009-06-04 19:14:27 | +---------------------+ |
TIMESTAMP
Хранит 4-байтное целое число, равное количеству секунд, прошедших с полуночи 1 января 1970 года по усреднённому времени Гринвича (т.е. нулевой часовой пояс, точка отсчёта часовых поясов). При получении из базы отображается с учётом часового пояса. Часовой пояс может быть задан в операционной системе, глобальных настройках MySQL или в конкретной сессии. Запомните, что сохраняется всегда количество секунд по UTC (универсальное координированное время, солнечное время на меридиане Гринвича), а не по локальному часовому поясу. Пример:
mysql> CREATE TABLE tm1 (col TIMESTAMP NOT NULL); mysql> SET @@SESSION.time_zone = '+00:00'; mysql> SELECT now(); +---------------------+ | now() | +---------------------+ | 2009-06-04 18:24:54 | +---------------------+ mysql> INSERT INTO tm1 VALUES(now()); mysql> SELECT * FROM tm1; +---------------------+ | col | +---------------------+ | 2009-06-04 18:25:08 | +---------------------+ mysql> SET @@SESSION.time_zone = '+01:00'; mysql> SELECT now(); +---------------------+ | now() | +---------------------+ | 2009-06-04 19:25:21 | +---------------------+ mysql> INSERT INTO tm1 VALUES(now()); mysql> SELECT * FROM tm1; +---------------------+ | col | +---------------------+ | 2009-06-04 19:25:08 | | 2009-06-04 19:25:26 | +---------------------+ mysql> SET @@SESSION.time_zone = '+00:00'; mysql> SELECT * FROM tm1; +---------------------+ | col | +---------------------+ | 2009-06-04 18:25:08 | | 2009-06-04 18:25:26 | +---------------------+ |
Ещё одно отличие! TIMESTAMP по умолчанию NOT NULL, а его значение по умолчанию равно NOW().
mysql> INSERT INTO dt1 VALUES(NULL); ERROR 1048 (23000): COLUMN 'col' cannot be NULL mysql> INSERT INTO tm1 VALUES(NULL); Query OK, 1 ROW affected (0.00 sec) mysql> SELECT * FROM tm1; +---------------------+ | col | +---------------------+ | 2009-06-04 18:25:08 | | 2009-06-04 18:25:26 | | 2009-06-04 18:32:50 | +---------------------+ |
Дополнение. Для тех, кого смущает использование функции NOW().
mysql> SET @@SESSION.time_zone = '+00:00'; mysql> INSERT INTO dt1 VALUES('2009-06-04 22:00:00'); mysql> SET @@SESSION.time_zone = '+01:00'; mysql> SELECT * FROM dt1; +---------------------+ | col | +---------------------+ | 2009-06-04 22:00:00 | +---------------------+ mysql> SET @@SESSION.time_zone = '+00:00'; mysql> INSERT INTO tm1 VALUES('2009-06-04 22:00:00'); mysql> SET @@SESSION.time_zone = '+01:00'; mysql> SELECT * FROM tm1; +---------------------+ | col | +---------------------+ | 2009-06-04 23:00:00 | +---------------------+ |