20 окт. 2000 г.

Азы linux (для детей) урок 33


Ваше текстовое окружение

Главное

Мы уже упоминали несколько переменных окружения, таких как PATH и HOME. До сих пор мы видели только примеры, в которых они используются в оболочке для определенной цели. Но в Linux существует множество других утилит, для нормальной работы которых необходима информация о вас.
Какая еще информация нужна программам, кроме путей и домашних каталогов?
Многим программам необходима информация о том, какой терминал вы используете; эта информация хранится в переменной TERM. В текстовом режиме, это будет эмуляция терминала linux, в графическом режиме, скорее всего, вы используете xterm. Многим программам требуется информация о предпочитаемом вами редакторе на случай, если они должны будут запускать редактор как дочерний процесс. Оболочка, которую вы используете, хранится в переменной SHELL, тип операционной системы - в OS и так далее. Список всех текущих переменных, определенных для вашей сессии, можно посмотреть, введя команду printenv.
Переменные окружения управляются оболочкой. В отличие от регулярных переменных оболочки, переменные окружения наследуются любой программой, которую вы запускаете, в том числе другой оболочкой. Новым процессам присваиваются копии этих переменных; процессы могут их читать, изменять и, в свою очередь, передавать собственным дочерним процессам.
В именах переменных нет ничего особенного, за исключением того, что по соглашению используют прописные буквы. Вы можете придумать любое имя, какое захотите, хотя существуют стандартные переменные, которые являются достаточно важными, поэтому они одинаковы во всех системах Linux, например PATH и HOME.

Экспорт переменных

Содержимое отдельных переменной обычно отображается с помощью команды echo, как в этих примерах:
debby:~> echo $PATH
/usr/bin:/usr/sbin:/bin:/sbin:/usr/X11R6/bin:/usr/local/bin

debby:~> echo $MANPATH
/usr/man:/usr/share/man/:/usr/local/man:/usr/X11R6/man
Если вы хотите изменить содержимое переменной таким, чтобы она была полезна для других программ, вам следует экспортировать новое значение из вашего окружения в окружение, которое запускают эти программы. Типичным примером является экспорт переменной PATH. Вы можете объявить ее добавлением очередного пути, например, с тем чтобы иметь возможность играть в симулятор полетов, который находится в /opt/FlightGear/bin:
debby:~> PATH=$PATH:/opt/FlightGear/bin
Такая запись указывает оболочке искать программ не только в текущем пути $PATH, но и в дополнительном каталоге /opt/FlightGear/bin.
Но если новое значение переменной PATH не известно окружению, то работать ничего не будет:
debby:~> runfgfs
bash: runfgfs: command not found
В Bash мы обычно делаем это с помощью одного элегантного шага:
export VARIABLE=value
Тот же самый способ используется для переменной MANPATH, которая сообщает команде man, где искать сжатые man-страницы. Когда новые программы устанавливаются в новые или необычные каталоги, документация для них, вероятно, также будет в нестандартных каталогах. Если вы хотите прочитать справочные страницы этих новых программ, расширьте переменную MANPATH:
debby:~> export MANPATH=$MANPATH:/opt/FlightGear/man

debby:~> echo $MANPATH
/usr/man:/usr/share/man:/usr/local/man:/usr/X11R6/man:/opt/FlightGear/man
Вы можете избежать повторного ввода этой команды в каждом окне, которое вы открываете, добавив эту строку в один из ваших установочных файлов оболочки, см. Раздел "Установочные файлы shell".

Зарезервированные переменные

Следующая таблица дает обзор наиболее распространенных предопределенных переменных:
Таблица. Стандартные переменные окружения
Имя переменной Хранимая информация
DISPLAY используется системой X Window для определения сервера, который отображает на дисплей
DOMAIN доменное имя
EDITOR хранит предпочитаемый вами редактор
HISTSIZE размер файла истории shell (в количестве строк)
HOME адресный путь вашего домашнего каталога
HOSTNAME имя локального хоста
INPUTRC определяет местоположение файлов устройств ввода, например, клавиатуры
LANG предпочитаемый язык
LOGNAME логин
MAIL местонахождение вашей папки для входящей почты
MANPATH пути поиска для man-страниц
OS строка, описывающая операционную систему
OSTYPE дополнительные сведения о версии и т.п.
PAGER используется программами, такими как man, которым требуется знать, что делать в случае, если вывод больше, чем окно терминала
PATH поиск путей для команд
PS1 первоначальное приглашение
PS2 вторичное приглашение
PWD текущий рабочий каталог
SHELL текущая оболочка
TERM тип терминала
UID ID пользователя
USER(NAME) имя пользователя
VISUAL ваш предпочитаемый полноэкранный редактор
XENVIRONMENT местонахождение ваших личных настроек поведения X
XFILESEARCHPATH пути поиска графических библиотек
Многие переменные не только предопределены, но также их значения устанавливаются заранее, при этом используются конфигурационные файлы. Мы обсудим это в следующем разделе.

Установочные файлы shell

При вводе команды ls -al для получения расширенного списка всех файлов, в том числе начинающихся с точки, содержащихся в вашем домашнем каталоге, вы увидите один или несколько файлов, начинающихся с . и заканчивающихся на rc. Для Bash это будет .bashrc. Это копия общесистемного конфигурационного файла /etc/bashrc.
При входе логина в shell, login выполнит идентификацию, установит окружение и запустит вашу оболочку. В случае bash следующим шагом будет чтение общего профиля из /etc, если такой файл существует. Затем bash ищет ~/.bash_profile, ~/.bash_login и ~/.profile в указанном порядке, читает и выполняет команды из первого, который существует и который можно прочитать. Если таких файлов нет, то используется /etc/bashrc.
Когда происходит выход их оболочки, bash считывает и выполняет команды из файла ~/.bash_logout, если он существует.
Эта процедура подробно описана в man-страницах login и bash.

Стандартный набор установочных файлов

Пример /etc/profile

Давайте посмотрим на некоторые из этих конфигурационных файлов. Первый для чтения — это /etc/profile, в котором устанавливаются такие важные переменные, как PATH, USER и HOSTNAME:
debby:~> cat /etc/profile
# /etc/profile

# System wide environment and startup programs, for login setup
# Functions and aliases go in /etc/bashrc


# Path manipulation
if [ `id -u` = 0 ] && ! echo $PATH | /bin/grep -q "/sbin" ; then
    PATH=/sbin:$PATH
fi

if [ `id -u` = 0 ] && ! echo $PATH | /bin/grep -q "/usr/sbin" ; then
    PATH=/usr/sbin:$PATH
fi

if [ `id -u` = 0 ] && ! echo $PATH | /bin/grep -q "/usr/local/sbin"
    then
    PATH=/usr/local/sbin:$PATH
fi

if ! echo $PATH | /bin/grep -q "/usr/X11R6/bin" ; then
    PATH="$PATH:/usr/X11R6/bin"
fi
Эти строки проверяют устанавливаемые пути: если root открывает оболочку (ID пользователя 0), проверяется пути /sbin, /usr/sbin и /usr/local/sbin. Если нет, то они добавляются. Для всех проверяется путь /usr/X11R6/bin.
# No core files by default
ulimit -S -c 0 > /dev/null 2>&1
Все, что не нужно отправляется в /dev/null, если пользователь не меняет эту настройку.
USER=`id -un`
LOGNAME=$USER
MAIL="/var/spool/mail/$USER"

HOSTNAME=`/bin/hostname`
HISTSIZE=1000
Здесь общим переменным назначаются их стандартные значения.
if [ -z "$INPUTRC" -a ! -f "$HOME/.inputrc" ]; then
    INPUTRC=/etc/inputrc
fi
Если переменная INPUTRC не установлена, и нет .inputrc в домашнем каталоге пользователя, то будет загружен файл, отвечающий за ввод по умолчанию.
export PATH USER LOGNAME MAIL HOSTNAME HISTSIZE INPUTRC
Все переменные экспортируются, поэтому они доступны для других программ, запрашивающих информацию о вашем окружении.

Каталог profile.d

for i in /etc/profile.d/*.sh ; do
    if [ -r $i ]; then
    	. $i
    fi
done
unset i
Все читаемые скрипты shell из каталога /etc/profile.d читаются и выполняются. Это то, что делает возможным color-ls, похожесть vi на vim, локальные настройки и т.д. Временная переменная i не устанавливается для предотвращения неадекватного поведения оболочки позже.

Пример .bash_profile

Затем bash ищет .bash_profile в домашнем каталоге пользователя:
debby:~> cat .bash_profile 
#####################################################
#                                                   #
#   .bash_profile file                              #
#                                                   #
#   Executed from the bash shell when you log in.   #
#                                                   #
#####################################################

source ~/.bashrc
source ~/.bash_login
В файле содержаться указания оболочке сначала прочитать ~/.bashrc, потом ~/.bash_login. При работе с окружением оболочки вы будете сталкиваться с встроенной в shell командой source достаточно часто: она используется для применения изменений конфигурации к текущему окружению.

Пример .bash_login

Файл ~/.bash_login определяет по умолчанию защиту файлов, устанавливая значение umask, см. Раздел "Вступление в другую группу". Файл ~/.bashrc используется для определения группы пользовательских псевдонимов, функции и личные переменных окружения. Сначала читается /etc/bashrc, который описывает стандартное приглашение (PS1) и значение по умолчанию umask. После этого вы можете добавить собственные настройки. Если нет ~/.bashrc, то по умолчанию читается /etc/bashrc.

Пример /etc/bashrc

Ваш файл /etc/bashrc может выглядеть следующим образом:
debby:~> cat /etc/bashrc
# /etc/bashrc

# System wide functions and aliases
# Environment stuff goes in /etc/profile

# by default, we want this to get set.
# Even for non-interactive, non-login shells.
if [ `id -gn` = `id -un` -a `id -u` -gt 99 ]; then
	umask 002
else
	umask 022
fi
Эти строки устанавливают значение umask. Затем, в зависимости от типа shell, устанавливается приглашение:
# are we an interactive shell?
if [ "$PS1" ]; then
  if [ -x /usr/bin/tput ]; then
    if [ "x`tput kbs`" != "x" ]; then 
# We can't do this with "dumb" terminal
      stty erase `tput kbs`
    elif [ -x /usr/bin/wc ]; then
      if [ "`tput kbs|wc -c `" -gt 0 ]; then 
# We can't do this with "dumb" terminal
        stty erase `tput kbs`
      fi
    fi
  fi
  case $TERM in
	xterm*)
	if [ -e /etc/sysconfig/bash-prompt-xterm ]; then
		PROMPT_COMMAND=/etc/sysconfig/bash-prompt-xterm
	else
   PROMPT_COMMAND='echo -ne "\033]0;${USER}@${HOSTNAME%%.*}:\
${PWD/$HOME/~}\007"'
	fi
    ;;
	*)
   [ -e /etc/sysconfig/bash-prompt-default ] && PROMPT_COMMAND=\
/etc/sysconfig/bash-prompt-default
	    ;;
    esac
    [ "$PS1" = "\\s-\\v\\\$ " ] && PS1="[\u@\h \W]\\$ "
    
    if [ "x$SHLVL" != "x1" ]; then # We're not a login shell
        for i in /etc/profile.d/*.sh; do
	    if [ -x $i ]; then
	        . $i
	    fi
	done
    fi
fi

Пример .bash_logout

Во время выхода из системы, выполняются команды из ~/.bash_logout, которые могут, например, очищать терминал, так что у вас появляется чистое окно при входе из удаленного сеанса или при выходе из системной консоли:
debby:~> cat .bash_logout
# ~/.bash_logout

clear
Давайте ближе рассмотрим, как эти скрипты работают в следующем разделе. Храните info bash под рукой.

Приглашение Bash

Введение

Приглашение Bash может делать гораздо больше, чем отображение такой простой информации, как имя пользователя, имя машины и некоторое указание на текущий рабочий каталог. Мы можем добавить другую информацию, такую как дата и время, количество подключенных пользователей и т.д.
Однако, прежде чем мы начнем, сохраним наше текущее приглашение в другую переменную окружения:
[jerry@nowhere jerry]$ MYPROMPT=$PS1

[jerry@nowhere jerry]$ echo $MYPROMPT
[\u@\h \W]\$

[jerry@nowhere jerry]$
Когда мы теперь будем изменять строку приглашения, например, с помощью команды PS1="->", то всегда сможем получить нашу оригинальную строку обратно с помощью команды PS1=$MYPROMPT. Конечно, вы получите ее обратно, и когда подключитесь снова; так будет до тех пор, пока вы возитесь с приглашением в командной строке и не вставляете его в файл конфигурации оболочки.

Некоторые примеры

Для того, чтобы понять эти приглашения и используемые управляющие последовательности, обратитесь к info- и man-страницам Bash.
  • export PS1="[\t \j] "
Отображает время и количество выполняемых заданий.
  • export PS1="[\d][\u@\h \w] : "
Отображает дату, имя пользователя, название хоста и текущую рабочую директорию. Заметьте, что \W отображает только конечные имена текущего каталога.
  • export PS1="{\!} "
Отображает номер каждой команды в истории.
  • export PS1="\[\033[1;35m\]\u@\h\[\033[0m\] "
Делает user@host розовым.
  • export PS1="\[\033[1;35m\]\u\[\033[0m\] \[\033[1;34m\]\w\[\033[0m\] "
Раскрашивает имя пользователя в розовый цвет, а рабочий каталог в голубой.
  • export PS1="\[\033[1;44m\]$USER is in \w\[\033[0m\] "
Приглашение для людей, которым трудно видеть разницу между приглашением и тем, что они вводят.
  • export PS1="\[\033[4;34m\]\u@\h \w \[\033[0m\]"
Подчеркнутое приглашение.
  • export PS1="\[\033[7;34m\]\u@\h \w \[\033[0m\] "
Белые символы на синем фоне.
  • export PS1="\[\033[3;35m\]\u@\h \w \[\033[0m\]\a"
Розовая строка иным шрифтом, которая предупреждает вас, когда ваши команды закончили работу.
  • export PS1=...
Переменные экспортируются, так что впоследствии выполняющиеся команды также будут знать об окружении. Для конфигурации строки приглашения лучше изменить конфигурационный файл оболочки, ~/.bashrc.
Если вам захочется, то приглашения могут выполнять shell-скрипты и вести себя по-разному в зависимости от условий. У вас может даже строка приглашения играть мелодию при выполнении команды, хотя это вам быстро надоест. Более подробную информацию можно найти в Bash-Prompt HOWTO.

Сценарии оболочки

Что такое сценарии?

Скрипт оболочки, как мы видели в примерах конфигурации shell, представляет собой текстовый файл, содержащий команды оболочки. Когда такой файл используется в качестве первого аргумента без опции при вызове Bash, и без опций -c или -s, Bash считывает и выполняет команды из файла, затем выходит. Этот режим работы создает неинтерактивную оболочку. Когда Bash запускает shell-скрипт, он устанавливает специальный параметр 0 к имени файла, а не имя к оболочке, и позиционные параметры (все, что следует за именем скрипта) устанавливаются в остальные аргументы, если таковые задаются. Если дополнительные аргументы не задаются, позиционные параметры не включаются.
Скрипт оболочки можно сделать исполняемым с помощью команды chmod за счет включения бита исполнения. Когда Bash находит такой файл при поиске в PATH по отношению к команде, он порождает подоболочку для его выполнения. Другими словами, выполнение
filename ARGUMENTS
эквивалентно выполнению
bash filename ARGUMENTS
если "filename" представляет собой исполняемый скрипт. Эта подоболочка инициализирует себя, так что эффект такой, как если бы новая оболочка интерпретировала сценарий, с тем исключением, что места команд, запомненные родителем (см. hash в info-страницах), сохраняются ребенком.
Большинство версий UNIX наделяют эту часть команд операционной системы исполняемым механизмом. Если первая строка сценария начинается с двух символов "#!", оставшаяся часть строки указывает интерпретатор для программы. Таким образом, вы можете указать bash, awk, perl или другой интерпретатор или оболочку и писать остальную часть файла сценария на этом языке.
Аргументы для интерпретатора состоят из одного дополнительного аргумента, который следует за именем интерпретатора в первой строке файла сценария, после следует имя файла сценария, а затем остальные аргументы. Bash будет выполнять это действие на операционных системах, которые не обрабатывают это самостоятельно.
Сценарии Bash часто начинаются с
#! /bin/bash
(предполагая, что Bash была установлена в /bin), так как это гарантирует использование Bash для интерпретации сценариев, даже если скрипт выполняется под другой оболочкой.

Некоторые простые примеры

Очень простой скрипт, состоящий только из одной команды, которая приветствует пользователя, выполняется так:
[jerry@nowhere ~] cat hello.sh
#!/bin/bash
echo "Hello $USER"
Сценарий фактически состоит только из одной команды echo, которая использует значение ($) переменной окружения USER, чтобы напечатать строку, настроенную на пользователя, который вызывает скрипт.
Другой однострочный пример, используемый для отображения подключенных пользователей:
#!/bin/bash
who | cut -d " " -f 1 | sort -u
Вот скрипт, состоящий из несколько строк, которые я использую, чтобы создать резервные копии всех файлов в каталоге. Сначала скрипт создает список всех файлов в текущем каталоге и помещает его в переменную LIST. Затем он устанавливает имя копии для каждого файла, и затем копирует файл. Для каждого файла выводится сообщение:
tille:~> cat bin/makebackupfiles.sh
#!/bin/bash
# make copies of all files in a directory
LIST=`ls`
for i in $LIST; do
	ORIG=$i
	DEST=$i.old
	cp $ORIG $DEST
	echo "copied $i"
done
Просто ввод строки подобной mv * *.old не будет работать, как вы заметите при попытке выполнить это на ряд тестовых файлов. Команда echo была добавлена для отображения какой-либо деятельности. echo обычно полезна, когда сценарий не работает: постепенно просматривая код, вы найдете ошибку в кратчайшие сроки.
Каталог /etc/rc.d/init.d содержит множество примеров. Давайте посмотрим на этот сценарий, который управляет фиктивным сервером IcanSeeYou:
#!/bin/sh
# description: ICanSeeYou allows you to see networked people

# process name: ICanSeeYou
# pidfile: /var/run/ICanSeeYou/ICanSeeYou.pid
# config: /etc/ICanSeeYou.cfg

# Source function library.
. /etc/rc.d/init.d/functions

# See how (with which arguments) we were called.
case "$1" in
	start)
		echo -n "Starting ICanSeeYou: "
		daemon ICanSeeYou
		echo
		touch /var/lock/subsys/ICanSeeYou
		;;
	stop)
		echo -n "Shutting down ICanSeeYou: "
		killproc ICanSeeYou
		echo
		rm -f /var/lock/subsys/ICanSeeYou
		rm -f /var/run/ICanSeeYou/ICanSeeYou.pid
		;;
	status)
		status ICanSeeYou
		;;
	restart)
		$0 stop
		$0 start
		;;
	*)
		echo "Usage: $0 {start|stop|restart|status}"
		exit 1
esac

exit 0
Во-первых, размещается . (точка), которая управляет множеством функций оболочки и используется практически во всех скриптах в /etc/rc.d/init.d. Затем размещается команда case, которая определяет 4 различных способа выполнения сценария. Например, это может быть ICanSeeYou start. Решением в этом случае будет чтение (первого) аргумента сценария с выражением $1.
Когда дается не совместимый вход, то срабатывает код, отмеченный звездочкой, в котором скрипт выдает сообщение об ошибке. Список case заканчивается инструкцией esac. В случае start программа сервера запускается как демон, и назначаются ID процесса и шлюз. В случае stop процесс сервера сходит на нет и останавливается, шлюз и PID удаляются. Опции, такие как опции daemon и функции как killproc определены в файле /etc/rc.d/init.d/functions. Эта установка специфична для дистрибутива, используемого в этом примере. Запускающие скрипты в вашей системе могут использовать другие функции, определенные в других файлах, или вообще никакие.
В случае успеха сценарий возвращает код выхода нуля к его родителю.
Этот сценарий является прекрасным примером использования функций, которые позволяют легче читать сценарий и делать работу быстрее. Заметьте, что здесь используется sh вместо bash, чтобы сделать их полезными для более широкого круга систем. В системе Linux, вызывая bash как sh, результаты в оболочке работают в POSIX-совместимом режиме.
Man-страницы bash содержат больше информации об объединении команд, for- и while-петлях, регулярных выражений, а также примеры. Понятный Bash для системных администраторов и опытных пользователей, с упражнениями, от того же автора, как "Введение в руководство Linux", находится на http://tille.garrels.be/training/bash/. Подробное описание особенностей Bash и приложений есть в справочном руководстве "Продвинутые сценарии Bash".