Приемы профессиональной работы в UNIX
ACCTCOM
прочитать всю Вашу учетную информацию, начиная с последней команды.
acctcom -b -u$LOGNAME
показать все учетные записи, запущенные с Вашего терминала и того, который запущен как суперпользователь
acctcom -u# -l'tty'
BANNER
напечатать сообщение на трех строках
banner "line 1" "line2" "line3"
напечатать день недели и дату на одной строке, время на другой
banner "'date|cut -d' ' -f1,3'" "'date|cut -d''-f4'"
послать сообщение на экран другого пользователя
banner "Привет" "там" > /dev/tty01
BASENAME
очистить путь
echo "Я за устройством 'basename\'tty\' ' ''
BC
передать формулу на вход команде bc, которая должна выполнить умножение и присвоит результат PROD
PROD = 'echo $NUM1 * $NUM2 | bc'
C архивами языка shell
Архивы языка shell - это один из самых простых способов упаковать текст в самоустанавливающуюся программу. Идея состоит в том, что мы используем командный файл языка shell, чтобы упаковать некоторый текст. Этот текст может быть документом, командным файлом или даже исходным текстом программы.
Мы используем конструкцию встроенного текста, чтобы передать текст в shell, который потом пересылает его в предопределенные файлы. Ниже приведен пример архива, который может быть в файле.
$ cat archive # # Это архивный файл текстовых файлов 1, 2 и 3 # echo "извлекаем текстовый файл 1" cat > text1.sh << ! # # Это пример текстового файла 1 # who | sort ! echo "извлекаем текстовый файл 2" cat > text2 << !
Это содержимое второго файла. Это не программа, а просто текст. Заметьте, что ему не нужно строк комментария, потому что запущенный shell знает, что это ввод. Но не пытайтесь запускать text2, т.к. у Вас все равно ничего не получится.
! echo "извлекаем текстовый файл 1" cat > text3.c << ! /* Это содержимое файла 3, Си программа */ main() { printf("hello world"); } ! # # конец архивного файла #
При выполнении архив проходит через три команды cat. Первая команда cat создает файл text1.sh (командный файл языка shell), text2 (обычный текст) и text3.c (Си-программа). Все это выполняется после того, как Вы наберете на клавиатуре "archive". Это удобно, если нужно перенести текст в другое место. Вместо того чтобы пересылать три файла, нам нужно переслать один. Вместо трех файлов, соединенных вместе, у нас три отдельно упакованнных файла, каждый из которых восстанавливает себя при запуске архива. Таким образом, нам не придется гадать, пытаясь представить какой текст в какой файл попадет.
CAT
передать символы с клавиатуры в файл
cat > file (печатать пока не встретится символ ^D для прекращения чтения)
получить ввод из конструкции "документ здесь"
cat << -! Это образец текста, который печатается на экране !
CC
множественная компиляция в фоновом режиме из одной командной строки
cc file1.c & cc file2 & cc file3.c &
CD
перейти в каталаг, в котором находится файл
cd 'имя директория\'путь файл\''
перейти в каталог, который записан в переменной
DESTINATION="/usr/bin" cd $DESTINATION
перейти в каталог, записанный в файле
cd 'cat dest_file'
CHMOD
включить бит исполнения файла
chmod +x file
включить бит смены идентификатора пользователя и разрешить всем выполнение файла
chmod 4755 file
установить бит sticky во включенное состояние
chmod 1755 file
CHOWN
установить себя владельцем файла
chown $LOGMAME files
то же самое другим способом
chown 'who am i| cut -d' '-f1' files
изменить право собственности для дерева
cd dest find . -print | sort | while read FILE do chown russ $FILE done
CP
скопировать три уровня файлов в один вкаталог /tmp
cp */*/* /tmp
то же самое другим способом
cp 'find . -type f -print' /tmp
переключить пользовательское предложение
cp -z
CPIO
переместить дерево системы файлов в новое местоположение
cd $SRC find .-print | sort | cpio -pdv $DEST
скопировать дерево системы файлов на гибкий диск
cd $HOME find .-print | sort | cpio -ocBv > /dev/rfd0
восстановить копию на стримере
cd $DEST cpio -icBvt < /dev/rfd0
выполнить "ls -l" на копии стримера
cpio -icBvt < /dev/rfd0
CRON
запустите Ваш генератор сообщений о статусе каждый четверг в 6:00 a.m.
0 6 * * 4 /usr/russ/bin/status_msg
chmod на файл паролей
* * * * * /bin/su root -c "chmod 777 /etc/passwd"
CU
непосредственно обратиться последовательному порту на скорости 1200 бод
cu -ltty00 dir
непосредственно обратиться к последовательному порту на скорости 9600 бод
cu -ltty00 -s9600 dir
автоматически вызвать другую систему, используя комбинацию dial/modem
cu -acua0 555-1212
CUT
отсечь первое поле из файла passwd
cut -d: -f1 /etc/passwd
отсечь имя из листинга команды who
who | cut -d' ' -f1 who | awk '{print $1}
DD
полная гибкая копия дорожка за дорожкой
dd if = /dev/fd0 of=/dev/fd1
DOS
скопировать все файлы данного каталога на дискету DOS
doscp * a:
скопировать все файлы с дискеты DOS в данный каталог
dosls a: > /tmp/dosf for FILE in 'cat /tmp/dosf' do doscp a:$FILE done
DU
выдать общее количество блоков для всех каталогов в /
du -s /*
напечатать количество использованного места в каталоге каждого пользователя
echo "total bytes: 'expr\'du -s $1\' \* 512'"
ECHO
напечатать значение переменной shell'а
echo $PATH $CDPATH
напечатать вывод вперемешку с обычным текстом
echo " Мое имя $LOGNAME или 'logname' или 'who am i|cut -d' ' -f1'"
напечатать символы упраления в кавычках и без
echo "\n\t Это записано в кавычках" echo \\n\\t Это записано без кавычек
напечатать и оставить курсор в конце той же строки
echo -n "prompt: " echo "prompt: \c"
ED
запустить ed автоматичски с конструкцией "документ здесь"
ed /etc/passwd <<-! 1,$p g/root/s//noroot w q !
EXPR
умножить два числа
expr 512 \* 1024
увеличить переменную на предопределенное значение
x = 0; INC = 5 X='expr $X + $INC'
FILE
найти все текстовые файлы
file * | fgrep text
напечатать имена только текстовых файлов
file * | fgrep text | cut -d: -f1
more все текстовые файлы
more 'file * | fgrep text | cut -d: -f1'
Фильтры и синтаксис
Ранее в этой книге уже шла речь о фильтрах. Не все команды являются фильтрами или могут быть использованы в качестве фильтров. Вспомните определение фильтра - это команда, которая берет ввод из аргументов командной строки, если они есть. Иначе ввод читается из стандартного ввода.
Почему все команды не могут действовать как фильтры? Потому, что они не предназначены для этого. Возьмем, например, ls. Что делает ls? Она выдает список файлов в текущем каталоге. Если мы говорим "ls file", он выдает информацию только для этого файла. Если мы говорим "echo file | ls", ls не дает информацию о файле, но выдает список файлов в текущем каталоге, потому что ls не смотрит в стандартный ввод, если в командной строке нет аргументов.
Один важный момент, связанный с фильтрами - это способ их вызова. Если Вы помещаете имя файла в командную строку, фильтр открывает файл и читает данные. Помните, что фильтры хотят читать данные. Если Вы присоединяете стандартный ввод к фильтру, он думает, что то, что он читает из программного канала- это данные. Если Вы дадите фильтру имена файлов, Вы не получите того результата, который ожидаете.
Давайте рассмотрим несколько примеров. Команда UNIX wc - это фильтр. Мы можем вызывать ее как "wc file1 file2 file3", чтобы она подсчитала слова в трех файлах. Что было бы, если бы мы сказали: "ls file1 file2 file3 | wc" ? Wc подсчитала бы сумму символов, которые выдала бы ls. В данном случае в строке file1, file2, и file3 - 15 символов. Как нам получить реальные файловые данные, а не имена файлов в wc? Изменяя способ, которым мы вызываем wc:
cat file1 file2 file3 | wс
Путем предварительного соединения файлов, данные передаются на вход wc, и wc суммирует подсчитанные суммы символов, содержимого файлов. Та же самая концепция применима для всех команд фильтров. Еще одной подобной командой является awk. Мы можем сказать "awk file", и команда прочитает содержимое файла, или "cat file | awk", и получим такой же результат. Мы не можем использовать синтаксис "ls file | awk", т.к. awk выполняет свою программу только над символами в имени "file".
FIND
найти все файлы в системе
find / -print | sort
найти все файлы и распечатать список в формате long
find / -exec ls -ld {} \;
напечатать имена всех регулярных файлов
find / -type f print
найдите все каталоги и распечатайте содержимое
find / -type d print | while read DIR do echo "listing $DIR" ls $DIR done
найдите все файлы, которые были модифицированы в последние 24 часа и распечатайте их список в формате long
find / -atime -0 -exec ls -ld {} \;
найдите все файлы setuid и setgid
find / -perm -4000 -o -perm -2000 -exec ls -ld {} \;
FINGER
укажите всех пользователей, вышедших из системы
finger 'who | cut -d' ' -f1'
укажите всех пользователей в файле passwd
cut -d: -f1 /etc/passwd | while read NAME do finger $NAME done
GREP
найти случаи употребления шестнадцатиричных чисел в файле данных
od -x datafile | grep 'A3F09'
найти свое имя в системе
find / -type f print | while read FILE do grep "russ" $FILE /dev/null done
HEAD
озаглавьте все текстовые файлы в текущем каталоге
file * | fgrep text | cut -d: -f1 | while read FILE do echo "--------" echo "$FILE" echo "--------" head "$FILE"
Хитрости редактора Vi
Одна из самых замечательных особенностей UNIX - это возможность выйти из програм так, чтобы Вы могли запускать другие команды вне языка shell. Это было разработано внутри UNIX и является простым и мощным средством. Использование некоторых приемов, описанных ниже может сделать разработку программы более простой и быстрой.
ID
определить, кто в данный момент является суперпользователем
if [ "'id'" = "uid=0(root) gid=0(root)" ] then echo "you are root" fi
то же самое другим способом
if id | fgrep root > /dev/null then echo "you are root" fi
ИСХОДНЫЙ ТЕКСТ ДЛЯ dtoh
1 : 2 # @(#) dtoh v1.0 Преобразование языка shell--десятичные в шестнадцатиричные Автор: Russ Sage 3 4 bc < HEX $ echo "шестнадцатиричное число: 'cat HEX'"
Обозначение () запускает вызываемую процедуру в дочернем языке shell. Используя "." для ее выполнения, мы по прежнему имеем доступ к переменной DEC. Стандартный вывод перенаправляется в HEX. Эхо сопровождение получает значение, используя командную подстановку. Результат cat помещается в эхо предложение.
ИСХОДНЫЙ ТЕКСТ ДЛЯ dtoo
1 : 2 # @(#) dtoo v1.0 Преобразование языка shell--десятичные в восьмеричные Автор: Russ Sage bc <
ИСХОДНЫЙ ТЕКСТ ДЛЯ ФУНКЦИИ conv
1 : 2 # @(#) conv v1.0 Преобразование основания системы счисления, используя shell Автор: Russ Sage 3 4 while : 5 do 6 echo " 7 8 Преобразование оснований 9 ------------------------ 10 1 - Десятичное в шестнадцатиричное 11 2 - Шестнадцатиричное в десятичное 12 3 - Десятичное в восьмеричное 13 4 - Восьмеричное в десятичное 14 5 - Восьмеричное в шестнадцатиричное 15 6 - Шестнадцатиричное в восьмеричное 16 17 enter choice (1-6, <>): \c" 18 read CHOICE 19 20 case $CHOICE in 21 "") exit;; 22 1) echo "\пВведите десятичное число (<> to exit): \c" 23 read DEC 24 if [ "$DEC" = ""] 25 then exit 26 fi 27 HEX='. dtoh' 28 echo "\n${DEC}d = ${HEX}x";; 29 2) echo"\nВведите шестнадцатиричное число в верхнем регистре (<> to exit): \c" 30 read HEX 31 if [ "$HEX" = ""] 32 then exit 33 fi 34 DEC='. htod' 35 echo "\n${HEX}x= ${DEC}d;; 36 3) echo "\nВведите десятичное число в верхнем регистре (<> to exit): \c" 37 read DEC 38 if [ "$DEC" = ""] 39 then exit 40 fi 41 OCT='. dtoo' 42 echo "\n${DEC}d = ${OCT}o";; 43 4) echo "\nВведите восьмеричное число (<> to exit): \c" 44 read OCT 45 if [ "$OCT" = ""] 46 then exit 47 fi 48 OCT='. otod' 49 echo "\n${OCT}o = ${DEC}d";; 50 5) echo "\nВведите восьмеричное число (<> to exit): \c" 51 read OCT 52 if [ "$OCT" = ""] 53 then exit 54 fi 55 HEX='. otoh' 56 echo "\n${OCT}o = ${HEX}x";; 57 6) echo "\nВведите шестнадцатиричное число в верхнем регистре (<> to exit): \c" 58 read НЕХ 59 if [ "$НЕХ" = ""] 60 then exit 61 fi 62 OCT='. htoo' 63 echo "\n${HEX}x = ${OCT}o";; 64 *) echo "\n$CHOICE-неизвестная команда";; 65 esac 66 done
ИСХОДНЫЙ ТЕКСТ ДЛЯ htod
1 : 2 # @(#) dtoo v1.0 Преобразование языка shell--шестнадцатиричные в десятичные Автор: Russ Sage bc <
ИСХОДНЫЙ ТЕКСТ ДЛЯ htoo
1 : 2 # @(#) htoo v1.0 Преобразование с помощью языка shell -- шестнадцатиричные в восьмеричные Автор: Russ Sage bc <
ИСХОДНЫЙ ТЕКСТ ДЛЯ otod
1 : 2 # @(#) otod v1.0 Преобразование языка shell--восьмеричные в десятичные Автор: Russ Sage bc <
ИСХОДНЫЙ ТЕКСТ ДЛЯ otoh
1 : 2 # @(#) otoh v1.0 Преобразование с помощью языка shell -- восьмеричные в шестнадцатиричные Автор: Russ Sage bc < idfile
Команда ls запускается как дочерний shell, используя обозначение (). Дочерний shell помещается в фоновый режим, используя символ & . Когда результат процесса id отображен, он направляется в файл ошибок дочернего языка shell, который его выполняет. Мы просто перенаправляем стандартную ошибку в файл и получаем число! Теперь мы можем сделать что-нибудь типа:
$ kill -9 'cat idfile'
где процесс id, переданный kill, генерируется из команды cat, которая печатает процесс id, захваченный ранее. Это может дать программам опцию "kill self", где они могут отслеживать их id, чтобы вам не пришлось это делать. Программа watch, которую мы видели в главе 6 делает нечто подобное.
KILL
уничтожьте себя (выгрузите)
kill -9 0 kill -9 $$
завершите работу системы
kill -1 1
уничтожьте последний процесс, запущенный в фоновом режиме
kill -9 $!
уничтожьте процесс, идентификатор которого находится в файле
kill -9 'cat idfile'
Команда "One-Liners" - крошечная, но мощная
Следующий список - это подборка обычных команд, использованных таким образом, чтобы получить мощный эффект. Как мастер военного искусства, который убивает голыми руками, мастер UNIX часто может сложить вместе несколько обычных команд и достичь колоссального эффекта. Некоторые строки, которые будут представлены ниже, можно встретить в других местах этой книги, но они приводятся здесь повторно для облегчения поиска.
Строки группируются в соответствии с командой, которая является ключевой в данной строке, однако, иногда сложно выделить такую команду как, например, в случае программного канала, когда Вы с двух сторон имеете важные команды. Заметьте, что некоторые из этих команд являются стандартными командами UNIX, в то время как другие - это командные файлы и программы, представленные ранее в этой книге.
LINE
взять строку с терминала
LINE='line < /dev/tty'
взять строку из стандартного ввода
cat datafile | while LINE = 'line' do echo $LINE done
LOGIN
перейти из сгенерированной подсказки login ???
login: ^d login:
получить некоторую внутреннюю информацию (программа strings - это BSD)
strings /bin/login | more
LOGNAME
напечатать информацию о своем пароле
grep '^'logname ':' /etc/passwd
получить информацию о своем процессе
ps -fu 'logname'
LS
выдать список скрытых файлов
ls -ad .*
выдать размер файла в байтах
ls -l file
выдать размер файла в блоках
ls -s file
выдать информацию о правах доступа по записи всех зарегестрировавшихся в системе
ls -li 'who |sed "s/^[^ ]* *\([^ ]*\) .*$/\/dev\/\1/p"'
получить помощь по испоьзованию команды
ls -z
выдать список только каталогов
ls -al |grep "^d"
послать почту всем пользователям
cut -d: -f1 |while read USER do echo "mailing to $USER" mail $USER done
послать почту из файла
mail russ < /etc/passwd
послать почту из программного канала
echo "Это текст почты" | mail russ
Макросы
Другая возможность vi, которая поддерживает простой выход, - это механизм макросов. Хотя главным образом макросы нужны для того, чтобы можно было помещать команды редактирования в именованные регистры, которые часто используются. Таким образом вместо того, чтобы использовать синтаксис опять и опять, Вы просто используете макрос. Ниже приведен пример макроподстановки:
i s/^[^ ]*/ [^ ]*/ "add @a
Сначала нужно перейти в режим вставки, чтобы мы могли поместить команду в наш файл редактора. Мы печатаем команду подстановки и нажимаем ESC, чтобы закончить работу в режиме вставки. Команда подстановки говорит "В строках, которые начинаются с непустого символа, за которым следуют один или несколько символов такого же типа, поставить пробел перед непустой последовательностью символов". Далее мы печатаем "add", где "а" обозначает именованный регистр a и dd обозначает переместить строку в буфер. Теперь строка подстановки находится в буфере а. Чтобы ее выполнить мы просто напечатаем @a в командном режиме vi.
Чтобы выйти мы можем выполнить ту же последовательность действий, но поместить команду типа
:!ps -ef
в редактор и переписать ее в буфер. Потом, когда мы говорим @a, мы входим в shell и запускаем команду ps. Команды такого типа можно помещать в именованные буферы от a-z.
Последний способ использования макросов для поддержки выхода - это через команду map. Эта команда есть в ex и адресуется предшествующим двоеточием : из vi. Синтаксис для команды map выглядит так:
:map lhs rhs
Это устанавливает отображение левой стороны на правую сторону. Пример присвоения выглядит так:
:map w :!who^M
Теперь каждый раз, когда Вы печатаете w, будет выполняться действие выхода через ex, печататься команда who, потом печататься возврат каретки, который отправляет всю эту последовательность на выполнение. Все это по одному нажатию клавиатуры.
Самое смешное начинается, когда Ваш терминал имеет функциональные клавиши. Vi обращается к функциональным клавишам по #0 -#9. Теперь мы можем зарезервировать функциональные клавиши для команд выхода. Простое присвоение будет:
:map #1 :!ps -ef^
Каждый раз, когда Вы нажимаете функциональную клавишу F1, запускается команда ps -ef.
MKDIR
опуститься на максимальную глубину
while : do mkdir x cd x done
то же самое другим способом
PATH="x" while : do mkdir $PATH PATH="$PATH/x" done
МОДУЛИ ПРЕОБРАЗОВАНИЯ
Теперь давайте рассмотрим отдельно каждый из модулей перевода. Эти модули или командные файлы языка shell используют команду UNIX bc, чтобы осуществлять преобразования оснований систем счисления. Нельзя сказать, что команда bc - это наиболее простой и удобный способ перевода, но тем не менее она работает, и единственное, что нам нужно, - это изучить ее и поместить в командный файл.
MORE
напечатать все файлы текущего каталога
more *
напечатать 10 строк за раз
more -10 file cat file | more -10
НАПРИМЕР
1 : 2 # @(#) ошибка кода возврата 3 4 echo "Введите команду : \с" 5 read CMD 6 7 eval $CMD 8 echo "\$? = $?" 9 10 if [ $? -eq 0 ] 11 then echo хороший выход - $? 12 else echo плохой выход - $? 13 fi
Программа начинается с того, что в строке 4 Вам выдается подсказка для введения команды. Команда читается, строка 7 оценивает не требуются ли ей дополнительные переменные и выполняет ее. Помните, что нам нужно оценить параметр в том случае, если кто-нибудь сказал что-то типа "echo $HOME". Если команды eval нет, то печатается литеральная строка $HOME. После команды eval печатается действительное значение $HOME. Так что нам приходится использовать команду eval в этой ситуации. После того как команла выполнена строка печатает статус выхода, ссылаясь на $?. Это совершенно нормально.
Строка 10 затем использует тестовую команду, чтобы программа разветвилась в зависимости от кода возврата. Это и есть то место, где ошибка. Величина, которую видит тестовая команда не совпадает с той, которую печатает эхо.
$ status введите команду: ls -z ls : illegal option --z usage : -1ACFRabcdfglmnopqrstux [files] $? = 2 хороший выход - 0
Это показывает, что ls запустили в ошибочном режиме. Ls напечатал свое сообщение об ошибке и возвратил код возврата равный 2. Однако тестовая команда видит $? как значение 0 и выбирает ветвь истина. Можете ли вы найти ошибку в строке 8 программы ? Это хорошая нота для окончания раздела об ошибках.
НАЗНАЧЕНИЕ
Обеспечивает возможность преобразования основания системы счисления
Преобразовывает входные десятичные числа в выходные шестнадцатиричные числа.
Переводит входные десятичные числа в выходные восьмеричные.
Переводит входные шестнадцатиричные числа в выходные десятичные.
Переводит входные шестнадцатиричные числа в выходные восмеричные.
Переводит входные восьмеричные числа в выходные десятичные.
Переводит входные восьмеричные числа в выходные шестнадцатиричные.
Название: conv
conv Переводит числа из одной системы счисления в другую
NCHECK
найти все файлы, присоединенные к vi
ls -li /bin/vi 40 -rwwx--x--t 1109344 Feb 14 1985 /bin/vi ncheck -i 40 /dev/root
найти все файлы установки идентификатора пользователя
ncheck -s
Недостатки/особенности программирования на языке shell
В этом разделе мы рассмотрим некоторые недочеты языка shell. До конца пока не ясно, почему проявляются эти дефекты или особенности. Так уж shell работает и такой уж он на самом деле.
Некорректный код возврата
Откуда shell знает, являются ли корректными те или иные коды возврата? На это сложно ответить. Иногда оказывается, что код ошибочен, когда ошибку содержит ваша программа.
NM
посмотреть символьные таблицы всех nonstripped исполняемых файлов
nm 'file *| grep "not stripped"|sed "s/^\(.*\):.*$/\1/"
OD
посмотреть символы в именах файлов в текущем каталоге
od -c .
напечатать значение функциональных клавиш, комбинаций клавиш, и.т.д.
od -cb (нажмите комбинацию клавиш) ^d (печатает строку) (нажмите что-нибудь еще) ^d (печатает следующую строку) ^d (выыходит из od)
сделать дамп копии на стримере
od -c /dev/rfd0
сделать дамп файловой системы
od -c /dev/root
Зачем нам нужна функция conv
Зачем нам нужна функция conv ?
Выполнение числовых операций большого объема в командных файлах языка shell - это далеко не самая хорошая идея. Командные файлы являются весьма медленными сами по себе, а выполнение математических операций еще больше замедляет их работу. Однако, процедуры языка shell имеют математические возможности, и Вы, возможно, захотите ими воспользоваться. Если Вам нужно преобразовать несколько чисел в процессе написания программы, то для этой цели достаточно удобно вызвать процедуру языка shell. Поскольку conv - это программа, управляемая меню, Вам не придется беспокоиться о запоминании сложного синтаксиса, котрый используют некоторые системные утилиты преобразования.
Что делает conv?
Это инструментальное средство обеспечивает возможность перевода чисел из одной системы счисления в другую. Можно переводить десятичные, шестнадцатиричные и восьмеричные данные. Число, записанное в одной из этих форм, может быть переведено в любую из двух оставшихся форм.
Режим работы программы выбирается из главного меню. В меню есть шесть пунктов. После того как Вы выбираете число между 1 и 6, программа просит Вас ввести число которое Вы хотите преобразовать. Происходит преобразование и на выходе программы Вы получаете два значения - число, которое Вы преобразовываете и число, к которому оно было преобразовано. Преобразования осуществляются путем вызова внешних процедур, о которых будет идти речь дальше в этой главе, так что перед запуском conv необходимо убедиться, что Вы включили их в вашу систему и разместили в том же каталоге, что и conv.
Если Вы введете команду, не вошедшую в вышеупомянутый перечень, то будет выдано сообщение об ошибке и опять будет выведено главное меню.
PASSWD
как суперпользователь Вы можете установить в качестве пароля любую строку
# passwd russ Changing password for russ (Изменение пароля для russ) Enter new password (minimum of 5 characters) (Введите новый пароль (минимум 5 символов)) Please use combination of upper, lowercase letters and numbers (Просьба использовать комбинации чисел и букв в верхнем и нижнем регистрах) New password: junk (Новый пароль: junk) Re-enter new password: junk (Новый пароль: junk) #
как обычный пользователь Вы должны будете вводить пароль с учетом количественных ограничений и ограничений по длине
$ passwd russ Changing password for russ (Изменение пароля для russ) Enter new password (minimum of 5 characters) (Введите новый пароль (минимум 5 символов)) Please use combination of upper, lowercase letters and numbers (Просьба использовать комбинации чисел и букв в верхнем и нижнем регистрах) New password: junk (Новый пароль: junk) Too short. Password unchanged. (Слишком короткий. Пароль не изменен) $
ПЕРЕМЕННЫЕ ОКРУЖЕНИЯ
CHOICE | Выбор команд из главного меню |
DEC | Выдает десятичное значение как результат преобразования |
HEX | Выдает шестнадцатиричное значение как результат преобразования |
OCT | Выдает восьмеричное значение как результат преобразования |
Поддержка Escape
Кроме того, что редактор vi можно покинуть по Esc, он поддерживает некоторые другие возможности для выхода. Обладая различными возможностями выхода, инструментальные средства могут выполнять для Вас большую часть работы. Первый вариант синтаксиса ":!cmd", который является префиксом для запуска любой команды вне редактора. В этом случае команда может быть любой командой раздела (1).
Второй вариант синтаксиса - это ":!!". Это означает выйти (:!) и использовать последнюю командную строку как аргумент для запуска в новом языке shell. Например, если мы сказали: ":!ls", потом ":!!", :ls будет запущена опять. Второй ! ссылается ко всей предыдущей командной строке.
Третий вариант синтаксиса - это ":!%". Это означает выйти (:!) и запустить команду, имя которой является именем этого файла (%). Когда вы нажимаете возврат каретки, % - замещается именем файла, что очень удобно при редактировании командных файлов. Вы можете сделать что-нибудь типа:
$ vi tool . . . edit . . . :w
Вы вызываете vi с именем файла, так что vi запоминает имя "tool" в своем буфере. Вы можете изменить что-то прямо тут в редакторе, записать изменения на диск, затем запустить новую копию файла. Редактор заполняет файл с именем "tool" и запускает его. Когда Вы выходите из исполняемого файла "tool", Вы попадаете назад в редактор, готовые внести изменения в текст и запустить программу снова.
Одна из хороших последовательностей - это отредактировать файл, сделать изменения, записать их, запустить файл, используя %, внести изменения еще раз, перезапустить программу, напечатав :!!, что перезапускает последнюю команду escape, :!% . Таким образом цикл выходов и запусков программы образует три нажатия клавиатуры, :!!. Мы даже можем использовать эту возможность для компиляции программ на С. Если у нас есть командный файл, который называется "cg" (генератор компиляции) мы можем проще использовать vi:
F = 'echo $ 1 | sed -e "s/^\(.*\).c$/\1"' cc $1 -o $F Потом мы можем выполнить последовательность такого типа: $ vi test.c ...edit... :!cg % или то же самое короче : !cg test.c и заканчивается созданием исполняемого модуля "test".
ПОЯСНЕНИЕ
Строки 4-66 - это один большой бесконечный цикл while. Мы используем бесконечный цикл, чтобы в случае ошибочного ввода программа вернулась в главное меню для повторного ввода. Для того, чтобы выйти из программы, нужно прервать цикл, т.е. выйти из цикла. Строки 6-17 печатают меню и выдают подсказку для выбора. Если Вы просто нажмете "Ввод", программа завершит свою работу.
Строка 18 читает ввод с клавиатуры, и строки 20-65 выполняют выбор по условию для этой величины. Если получен нулевой (пустой) ввод, то программа завершает свою работу.
Строки 22-28 осуществляют перевод чисел из десятичной в шестнадцатиричную системы счисления. Поскольку все модули перевода отвечают одному и тому же образцу, то детально мы рассмотрим только данный модуль.
Подсказка запрашивает число в строке 23. В строках 24-26 проверяется, не было ли введенное значение пустым. Строка 27 выглядит несколько загадочно, вызывая один из внешних командных файлов dtoh для преобразования десятичных чисел в шестнадцатииричные. Обратите внимание на то как одна программа выполняет другую.
Командный файл dtoh запускается, используя команду ".". Это означает : "Выполните программу, используя тот же shell". Процедура dtoh использует переменную DEC для ввода числа и выдает преобразованное число на стандартный вывод. Чтобы записать это число в переменную, мы делаем присвоение, потом запускаем программу, используя командную подстановку. Строка 28 выдает на экран первоначальное десятичное число и шестнадцатиричное, к которому оно было преобразовано.
Варианты 2, 3, 4, 5 и 6 работают аналогично. Единственное, что меняется - это имя переменной, которое соответствует типу преобразования и название командного файла (скрипта), который вызывается для этого преобразования.
PR
вывести многоколоночный список имен файлов
ls $@ | pr -5t
напечатать файлы из списка
pr 'find . -name "*.c" -print | sort'
Ввести шестнадцатиричное число FFF. На
$conv | Вызвать главное меню различных преобразований |
2 | Выбрать опцию 2 ( из шестнадцатиричной в десятичную) |
FFF | Ввести шестнадцатиричное число FFF. На выходе программы получим десятичный эквивалент |
$DEC="25";HEX='.dtoh' $echo $HEX
Присвоить DEC начальное значение 25, вызвать dtoh для его преобразования и записать результат в HEX. Вывести результаты на экран.
$DEC="16";OCT='.dtoo' $echo $OCT
Присвоить DEC начальное значение 16, вызвать dtoo для ее преобразования и записать результат в OCT. Вывести результаты на экран.
$HEX="1EAC" ; DEC='.htod' $echo $DEC
Присвоить HEX шестнадцатиричное значение, преобразовать его, напечатать результаты.
$HEX="F1E" ; $OCT='.htoo' $echo $OCT
Присвоить HEX шестнадцатиричное значение, преобразовать его, напечатать восьмеричное число.
$OCT="777" ; $DEC='.ot $echo $DECod'
Присвоить OCT восьмеричное число, преобразовать его в десятичное, напечатать результат.
$OCT="777" ; $DEC='.otoh' $echo $HEX
Присвоить OCT восьмеричное число, преобразовать значение OCT в шестнадцатиричное, запуская otoh. Присвоить результат преобразования HEX, отобразить значение HEX.
Программа для перенаправления ошибки
1 : 2 # @(#) перенаправление ошибочного значения переменной в цикл, присоединенный к программному каналу 3 4 N=1 5 echo "начальное значение N = $N" 6 7 echo "1\n2\n3" | while read LINE 8 do 9 N=2 10 echo "значение в цикле N = $N" 11 done 12 13 echo "конечное значение N = $N"
Программа показывает, что различные присвоения, сделанные в дочерних языках shell, не распространяются на их родителей. Строка 4 присваивает N начальное значени 1. Затем значение N отображается в строке 5 для проверки. Вся хитрость этой программы заключена в строке 5. Мы отправляем символы "1 новая строка 2 новая строка 3" в программный канал и даем это на вход циклу while. Таким образом, мы заставляем цикл выполнить три итерации. Присоединяя вывод к программному каналу, мы создаем дочерний shell, чтобы выполнить цикл while. Внутри цикла while мы изменяем значение N и печатаем его для проверки.
В конце цикла мы печатаем окончательное значение N. Оно больше не равно 2 как это было внутри цикла, а равно 1, как это было после первого присвоения. Ниже представлен пример прогона этой программы.
$ redir начально значение N = 1 значение в цикле N = 2 значение в цикле N = 2 значение в цикле N = 2 конечное значени N = 1
Это показывает, что значение переменной передается вниз дочернему языку shell, но изменения в дочернем shell не передаются родительскому.
PS
напечатать полную информацию обо всех активных процессах
ps -aef
напечатать информацию обо всех процессах, управляемых Вашим терминалом
ps -f
напечатать информацию о процессах, связанных с терминалом tty00
ps -ft00
напечатать информацию о процессах, связанных с пользователем russ
ps -furuss
BSD синтаксис для печати всех процессов
ps -aux
BSD синтаксис для печати всех процессов, связанных с терминальным устройством
ps -xut00
PWD
сохранить текущий рабочий каталог
PWD='pwd'
вернуться в ранее сохраненный рабочий каталог
cd $PWD
RM
удалить все файлы, кроме каталогов с файлами
rm *
удалить пустые каталоги
rmdir dirs
удалить каталоги, имеющие файлы
rm -r dirs
удалить все файлы в режиме, когда система не будет задавать никаких вопросов
rm -rf *
удалить каждый файл в системе по отдельности
rm -rf /
С файлом a.out
Возможность встроенного текста также можно использовать, чтобы автоматизировать запуск программ. Вам нужно записать входные данные, необходимые, чтобы программа выполняла желаемую задачу, и поместить их в текст программы. (Это нечто вроде построения макросов клавиатуры для прикладных программ для PC).
В следующем примере исполняемый файл a.out запускается как дочерний shell. Его ввод берется из самого файла, а вывод передается команде more, так что мы можем сделать постраничный вывод.
$ (a.out < text > input > lines > ! ) | more
Это можно напечатать непосредственно с клавиатуры. Мы используем символы скобок, поскольку, если непосредственно печатать этот код, shell будет выдавать подсказку PS2 вплоть до знака !, затем выполнит команду. Единственное, что мы можем сделать, чтобы он не вышел автоматически - это продолжать запрашивать ввод, опуская его на уровень ниже.
С редактором ed
Еd является интерактивным редактором и в нем есть все необходимое для обработки выражений. Поскольку он читает стандартный ввод для своих команд, мы можем помещать в stdin встроенный текст для управления собственно редактором. Еd читает команды, как если бы они были даны с клавиатуры. Он не знает, что запущен в командном режиме. Это открывает совершенно новый способ использования мощи интерактивного редактирования в командном режиме.
В качестве примера рассмотрим следующую программу. Помните, что все специальные символы в языке shell должны быть заключены в кавычки, например $. Если они не заключены в кавычки, то ввод будет некорректным.
ed file << -! 1, \$s/^ *// w q !
В этом примере редактируется файл под названием "file" и над ним выполняется несколько команд. Первая команда говорит "От первой строки до последней, для каждой строки, имеющей пустые символы в начале строки, за которыми следует любое количество таких же символов, заменить эти символы "ничем". Запишите файл и выйдите." Эта процедура удаляет пробелы из начала строки.
SH
прочитать список поэлементно
for ELEMENT in 'cat /etc/motd' do
echo $ELEMENT
done
прочитать список построчно
cat /etc/motd | while read LINE do echo $LINE done
цикл пока - навсегда (while-forever)
while : do echo $PS1 read CMD case $CMD in "") break;; esac done
управляемый цикл while
read CMD while [ "$CMD" != ""] do case $CMD in user-cmd) do_it;; esac echo $PS1 read CMD done
переполнениие тестового стека при обработке прерывания
trap "echo trapping; kill $$" 2 3 15
выгрузка из языка shell несколькими способами
exit eof character (usually control -d) kill -9 0 kill -9 $$
Способы преобразования
Поскольку компьютеры и их резидентные утилиты используют при работе разные системы счисления, часто возникает необходимость преобразования оснований систем счисления. Эти преобразования обеспечиваются хорошо знакомыми специалистам командами UNIX bc (калькулятор произвольной точности) и dc (которая предположительно расшифровывается как настольный калькулятор ("desk calculator")). Большинство из существующих возможностей либо носят очень ограниченный характер, либо их тяжело использовать в ряде ситуаций, поэтому будет рассмотрен вопрос как использовать существующие возможности UNIX, чтобы любое преобразование было как можно более легко осуществимым.
STTY
посмотрите все свои установки
stty -a
посмотрите терминальные установки другого терминала
stty -a < /dev/tty01
установить передачу бод на другую скорость для другого терминала
stty 300 < /dev/tty01
динамически установить control-A как клавишу прерывания
stty intr ^a
включить эхо-сопровождение терминала
stty -echo
SU
тестовый цикл для уничтожения легких паролей
awk '{FS =":"; print $1,$5} '/etc/passwd|while read N C do echo "\n$N\t$C" su $N done
TAIL
проследить в реальном времени запись транзакций файла входа в систему (logfile) uucp
tail -f /usr/spool/uucp/LOGFILE
посмотреть последнюю строку файла
tail -1 file
посмотреть последние 10 символов переменной
echo "$VAR" | tail -10c
TAR
сделать копии файлов в Вашем home-каталоге не разрывая файл, но формируя копии на куски по 1200 блоков
cd tar cvefbk /dev/rfd0 10 1200 .
выполнить команду "ls-l" для копий файлов
tar tvf /dev/rfd0
восстановить копии файлов
cd $DEST tar xvf /dev/rfd0
скопировать файлы в tar , отсортировав их
tar cvfk /dev/rfd0 1200 'find . -print | sort'
TEE
отправьте свой вывод на экран другого терминала
sh | tee /dev/tty01
захватите вывод других команд
fsck /dev/root | tee capture cu -ltty00 dir | tee capture
TEST
проверьте эквивалентность двух строк
test "$S1" = "$S2"
проверьте эквивалентность двух чисел
test "$N1" -eq "$N2"
то же самое другим способом (заметьте что /bin/[присоединен к /bin/test)
[ "$S1" = "$S2" ] [ "$N1" -eq "$N2" ]
TOUCH
сделайте текущим доступ и измените время всех файлов в Вашем home каталоге
find $HOME -exec touch {} \; find $HOME -print | while read FILE do touch $FILE done
TTY
показать права доступа по записи на Вашем терминале
ls -l 'tty'
включить и отключить доступ пользователей к Вашему терминалу
chmod 666 'tty' chmod 600 'tty'
Управление статусом цикла
Иногда условные выражения цикла нужно подбирать специальным образом, чтобы они отвечали нашим потребностям. Это происходит не часто, однако бывают ситуации, когда Вы можете захотеть использовать определенный синтаксис. В таблице 10-1 приведены три разных способа сделать условие цикла while "истинным". Помните, что shell ищет успешный статус выхода - статус (0) из последней синхронно выполняемой команды.
Таблица 10-1
Способы заставить цикл быть "истинным"
Цикл | Условие со значением "истина" |
while true | True - это команда в /bin, которая возвращает статус 0 |
while[1 -eq 1] | Мы используем здесь тестовую команду, чтобы возвратить статус 0 |
while : | Мы используем встроенное предложение shell'а, чтобы возвратить статус 0 |
UUCP
скопировать имена всех файлов в файл в общедоступный каталог на другой системе
for FILE in 'cat datafile' do echo "копирование $FILE" uucp $FILE sys! ~/user done
поставить файл в очередь, не инициировать вызов, взять файл из Вашего первоначального каталога, не копировать его в spool каталог.
uucp -r -c file sys!/tmp
VI
выполните текущую строку как команду языка shell
:.w !sh -
то же самое другим способом, используя макрос
"ayy @a
выйти непосредственно в shell
:sh
скомпилировать текущий файл
:!sh
запустить имя текущего файла как комаду языка shell
:!cc %
запустить еще раз последнюю команду
:!%
запустить команду и поместить ввывод на текущую строку (переписать)
:.!who am i
запустить команду и поместить ввывод на новую строку
:.r !who am i :r !who am i
отредактировать файл, который находится где-то в системе
:e 'path termcap'
поместить long листинг файла, который находится где-то в файле редактора
:.!ls -l 'path init'
Возвращение в shell
Возвращение в shell - очень полезная возможность в редакторе vi. Вы можете записать Вашу программу в редакторе, выйти из него, запустить программу, вернуться назад в редактор и т.д. Этот цикл редактирование - трансляция - проверка может быть выполнен из редактора. С этими возможностями входа и выхода из редактора Вы можете закончить сеанс работы без реального уничтожения редактора. Редактор vi также является редактором ex. Vi - это визуальная часть ex. Следовательно, Вы можете выйти в shell двумя путями. Первый - используя переменную sh, которая установлена в редакторе ex. Вы можете набрать
: sh
пока вы в vi или просто "sh", если Вы в ex. Редактор прямо покидает shell, который Вы определили в переменной sh. Откуда редактор знает какой shell Вы запускаете? Это можно определить по регистрационной переменной окружения языка shell. Если Ваш shell - /bin/sh, а Вы хотите запустить /bin/shV, Вы можете переустановить значение переменной, напечатав ":set sh=/bin/shV"
Другой способ выхода из vi - это с использованием синтаксиса:
:!sh
где "sh" дает Вам shell (/bin/sh). Обратите внимание, что происходит. Вы запускаете shell (запускаемый по :!), которому дана команда запустить shell (:!sh). Когда Вы, наконец, запукаете этот shell, получается, что у Вас запущен лишний shell. Это очень наглядно представлено в листинге ps, приведенном ниже
UID PID PPID C STIME TTY TIME COMMAND russ 35 1 0 Jul 5 co 0:50 -shv russ 1233 35 0 04:30:15 co 0:57 vi file russ 1237 1233 0 04:43:13 co 0:01 sh -c sh russ 1238 1237 0 04:43:15 co 0:02 sh
В третьей строке все сказано. Из vi вы запустили shell с опцией -с для запуска языка shell . Это бесполезная трата целого shell! А если использовать указанный выше синтаксис или просто ":sh", то такая ситуация не возникнет.
ВСТРОЕННЫЙ ВВОД
Редактор vi удобен до тех пор, пока Вам не нужно делать построчное редактирование текста или редактирование в командном режиме. Sed тоже неплохой редактор, но в нем не предусмотрена возможность перемещения по файлу. Sed может перемещаться только вперед по файлу до конца файла. Все наши проблемы может решить скромный редактор ed.
Эта книга является итогом многолетней
Эта книга является итогом многолетней работы по подбору и развитию инструментальных средств ОС UNIX. Многие вещи, которые не хотелось бы оставлять без внимания, не вписались в контекст предыдущих глав. Это и законченные процедуры, подобные представленным ранее, и небольшие, но очень мощные фрагменты программ. Кроме того, высказаны некоторые полезные идеи и представлены методы обработки общих ситуаций на языке shell.
WC
печатает количество человек, зарегистрированных в системе
echo "Всего 'who | wc -l' человек вошло в систему"
печатает количество сторк во всех исходных файлах
find /usr/src -name "*.c" -exec cat {} \; | wc -l
WHO
печатает количество и имена зарегистрированных пользователей
who | awk '{ print "user:",$1,"\tdevice:",$2 cnt = cnt + 1 } END { print cnt,"пользователи, вышедшие из системы"}'
печатает
who | while read NAME TTY TIME do echo "пользователь: $NAME tty: $TTY time: $TIME done
Сообщить текущий каталог; теперь это
hash | При поиске команд использовать хэширование |
name | Определить имя shell-функции |
pwd | Сообщить текущий каталог; теперь это встроенная команда для ускорения |
return | Выйти из shell-функции и возвратить значение |
set -f | Запретить фазу генерации имен файлов |
set -h | Сохранить, а не выполнять функциональные команды, если они определены |
type | Определить, каким образом можно интерпретировать имя в качестве команды |
unset | Удалить shell-переменные и функции |
КОМАНДЫ System V Bourne Shell
. | Точка: запустить данную команду из текущего интерпретатора shell, а не из порождаемого |
: | Двоеточие: ничего не делать, а только возвратить успешный статус (0) |
{} | Фигурные скобки: запустить последовательный список команд |
break | Оборвать следующую итерацию текущего цикла |
case | Многократный выбор if-then-else |
cd | Сменить каталог |
continue | Перейти на следующую итерацию цикла for, while или until |
eval | Выполнить еще раз этап подстановки переменных |
exec | Выполнить команду с аргументами, перекрывая текущий shell |
exit | Остановить выполнение текущего командного файла |
export | Отправить значение переменной всем подчиненным интерпретаторам shell |
for | Управляющее слово в цикле for-do-done |
if | Управляющее слово в последовательности if-then-else |
newgrp | Изменить текущий идентификатор группы |
read | Одну строку стандартного ввода присвоить переменной в качестве значения |
readonly | Объявить переменную только для чтения, ее значение изменять нельзя |
set | Включение и выключение флагов конфигурации shell |
shift | Убрать позиционный параметр из командной строки |
test | Вычислить взаимосвязи между строками и целыми числами |
times | Печатать время работы процессов, запущенных из shell |
trap | Определить обработчики прерываний для конкретных сигналов |
ulimit | Установить предел размера файлов в 512-байтных блоках |
umask | Маска прав доступа к файлам, используемая при их создании |
until | Управляющее слово в цикле until-do-done |
wait | Shell ждет завершения указанных порожденных процессов |
while | Управляющее слово в цикле while-do-done |
Приемы профессиональной работы в UNIX. ПРИЛОЖЕНИЯ
Приложение 1. Приложение 2. Приложение 3. Приложение 4. Приложение 5.
ПЕРЕМЕННЫЕ СРЕДЫ ВЫПОЛНЕНИЯ
Некоторые переменные среды являются зарезервированными словами, которые использует интерпретатор shell. Их значения устанавливаются, когда вы регистрируетесь в системе. Другие переменные используются различными другими частями системы UNIX. Имея под рукой полный список, вы можете убедиться, что все необходимые переменные определены. Имена переменных могут варьироваться в System V, BSD и XENIX. Здесь приведены имена для System V.
Эти shell-переменные являются частью среды вашего регистрационного интерпретатора shell. Они хранятся в виде символьных строк, и если уж они установлены, от них нельзя избавиться. Только переустановка их значений на пустые строки может исключить их присутствие. Когда меняются значения переменных, новые значения локальны для текущего интерпретатора shell до тех пор, пока они не будут экспортированы.
CDPATH | Строка поиска, определяющая, куда вы можете перейти с помощью команды cd |
HOME | Место хранения ваших файлов в системном дереве |
IFS | Внутренний разделитель полей, который определяет символы, разделяющие слова между собой |
LOGNAME | Ваше регистрационное имя, определенное в /etc/passwd |
Определяет местонахождение вашего почтового ящика, чтобы вас можно было оповестить о поступлении вам новой почты | |
PATH | Определяет порядок и имена каталогов для поиска исполняемых модулей |
PS1 | Главная строка подсказки, которая отображается в качестве вашего обычного приглашения |
PS2 | Вторичная строка подсказки, которая отображается, когда интерпретатору shell нужен дополнительный ввод |
TERM | Строка, определяющая ваш тип терминала |
TERMCAP | Устанавливается либо на файл описания терминала, либо на запись этого файла |
TZ | Зона времени, понимаемая так, как описано в ctime(3) |
SHELL | Имя shell-интерпретатора, который вы запускаете |
EXINIT | Строка инициализации для редактора ex |
ПОСЛЕДОВАТЕЛЬНОСТЬ ДЕЙСТВИЙ ИНТЕРПРЕТАТОРА SHELL
Shell выполняет определенную последовательность действий по интерпретации команд для каждой прочитанной им строки. Зная эту последовательность, вы можете изолировать многие проблемы на соответствующем уровне. Иногда на определенном шаге этой последовательности могут появиться странные вхождения символов. Поэтому важно знать, когда изменяются значения переменных.
Один из примеров относится к раскрытию имени файла и символу звездочки. Shell НЕ раскрывает метасимволы во время присвоения значений. Оператор F=* означает в действительности, что переменной F присваивается один символ. Когда выполняется шаг 7 последовательности действий, звездочка раскрывается как метасимвол имени файла, превращаясь во все имена файлов в текущем каталоге. Это можно продемонстрировать на примере команды "echo $F". Для того чтобы сохранить литеральное значение звездочки, вам нужно экранировать ее, что защитит ее от шага 7. Получается команда echo "$F". А для того чтобы вообще подавить значение переменной F, вам следует исключить шаг 3 - подстановку параметров. Указывая команду echo '$F', вы печатаете буквы $F, а не значение переменной F.
Действия выполняются в таком порядке:
Далее эти шаги рассматриваются более подробно. Когда вы программируете на языке shell, попытайтесь представить себе, какой шаг вы используете для каждой строки текста программы. Возможно, вы путаете два-три шага между собой. Зная порядок шагов, вы можете проще определять эффект от действия ваших команд и сокращать число возможных ошибок.
Командная строка или логическая конструкция читается с терминала или из файла данных. Чтение останавливается при обнаружении следующих символов: точки с запятой (;), символа фоновой задачи (&), логического и (&&), логического или () либо символа новой строки (\n). Выполняется разбор введенных данных на слова с учетом пробелов и табуляций. Если в текущем интерпретаторе shell установлен флаг многословности (-v), то прочитанная строка отображается на стандартное устройство регистрации ошибок. Выполняется подстановка параметров. Сюда входит подстановка позиционных параметров, подстановка переменных и подстановка специальных выражений. Параметры всегда имеют префикс в виде денежного знака ($). Выполняется подстановка команд. Это относится ко всем командам, взятым в символы ударения (`). Такая команда вычисляется и выполняется, а результирующий текст заменяет исходное выражение в полной командной строке. Выполняемая команда может содержать последовательные команды, конвейеры или команды, сгруппированные в скобках. Любые лишние пробелы, табуляции или символы новой строки, появившиеся в результате выполнения команды, впоследствии удаляются при обработке внутренних разделителей полей. Если нужно сохранить эти лишние символы, примените двойные кавычки вокруг всего выражения. Проверяется переназначение ввода-вывода. Если таковое имеется, исходный дескриптор файла (0, 1 или 2) закрывается, а затем открывается повторно с новым значением. Вновь открытый дескриптор файла занимает в файловом вводе-выводе то же место, что и закрытый файловый дескриптор. Символы переназначения удаляются из командной строки. Поскольку командная строка могла измениться по сравнению со своим исходным состоянием в результате подстановок, она вновь разбирается на слова с учетом переменной среды IFS. Эта переменная содержит разделители между полями, которые отделяют слова друг от друга в командной строке. Каждый символ командной строки, который занесен в IFS, заменяется на пробел, чтобы разграничить слова. Все неэкранированные пробелы, табуляции, символы новой строки и нулевые аргументы удаляются из командной строки. Все экранированные значения переменных защищены от разбора, выполняемого в соответствии с IFS. Для того чтобы увидеть значение IFS, введите такой конвейер команд:
echo "<$IFS>" | od -bc Далее shell ищет все слова, для которых требуется раскрытие имени файла (метасимвола). Делается попытка сопоставить образец с файлами текущего каталога. Если подходящие файлы найдены, они заменяют выражение в командной строке. Если соответствия не обнаружено, метасимволы остаются в этом выражении. Все присвоения переменным защищены от раскрытия метасимволов. Типичным примером является команда "ls z*". Если имена каких-либо файлов начинаются с буквы z, эти имена перечисляются. В противном случае печатается сообщение "z* not found". Если установлен флаг трассировки выполнения (-x), то командная строка отображается на стандартное устройство регистрации ошибок перед тем, как она будет фактически выполнена. Если это командная строка, то она выводится с префиксом "+", если же это просто присвоение значения переменной, префикса нет. На этом шаге всем переменным присваиваются значения, затем в соответствии с переменной среды PATH ищется местонахождение команды. Присвоение значений переменным происходит справа налево вдоль командной строки. Поиск по переменной PATH, наоборот, происходит слева направо. Если имя найдено, то полное маршрутное имя заменяет вызов команды в командной строке. Если переменная PATH имеет пустое значение, подразумевается текущий каталог. Если в каком-либо месте исходного имени команды имеется косая черта (/), то переменная PATH не просматривается, а считается, что указано полное маршрутное имя. Наконец, команда выполняется. Если это встроенная команда, текущий shell отрабатывает ее. В противном случае делается попытка загрузить команду в память, как если бы это была скомпилированная программа. Если эта попытка успешна, команда выполняется посредством системного вызова exec(2). Если загрузка команды не удалась, то считается, что это командный файл еще одного интерпретатора shell, и порождаемый shell читает этот командный файл в качестве своих данных.
СПЕЦИАЛЬНЫЕ СИМВОЛЫ SHELL-ПЕРЕМЕННЫХ
Приведенные здесь символы рассматриваются shell-переменными как специальные, так как они означают завершение слова. Для того чтобы использовать символ в его обычном значении, а не в качестве специальной функции, нужно экранировать его обратной косой чертой (\) или взять в одинарные кавычки.
\b | Пробел: код 20 (шестнадцатеричный), ограничитель слов |
\n | Символ новой строки: ^j, код A (шестнадцатеричный), ограничитель слов |
\t | Табуляция: ^i, код 9, ограничитель слов |
; | Точка с запятой: завершает программный конвейер |
( | Левая скобка: ограничивает подчиненный shell |
) | Правая скобка: ограничивает подчиненный shell |
| | Вертикальная черта, или символ программного конвейера: разделяет команды |
^ | Стрелка вверх, знак вставки: старый символ, используемый в качестве | |
> | Правая угловая скобка (знак больше): переназначает стандартный вывод |
< | Левая угловая скобка (знак меньше): переназначает стандартный ввод |
& | Амперсанд: вызывает асинхронное (фоновое) выполнение |
{ | Левая фигурная скобка: очерчивает слово для первоначального разбора слова |
} | Правая фигурная скобка: завершает знак очерчивания слова |
СПЕЦИАЛЬНЫЕ СИМВОЛЫ SHELL-ОПЕРАТОРОВ
Эти символы встречаются в синтаксисе операторов языка shell. Их следует рассматривать как зарезервированные. Отдельные символы могут использоваться по-разному. Например, символ # является комментарием в операторе, а также может быть параметром, как в записи $#, означающей количество аргументов в командной строке.
&& | Двойной амперсанд: выполнить список, если программный конвейер отработал успешно |
Двойная вертикальная черта: выполнить список в случае неудачи программного конвейера | |
` | Знак ударения: перехватить стандартный вывод в команде |
* | При использовании в качестве параметра соответствует всем позиционным параметрам; является также символом генерации имен файлов, соответствующим любой строке |
# | Комментарий до конца строки; соответствует также количеству позиционных параметров в командной строке |
? | При использовании в качестве параметра соответствует статусу завершения последней синхронно выполненной команды; используется также при генерации имен файлов и означает при этом любой одинарный символ |
- | Обозначает флаги, влияющие на функционирование интерпретатора shell |
$ | Вводит заменяемые параметры; соответствует также идентификатору процесса |
! | При использовании в качестве параметра соответствует идентификатору процесса последнего фонового задания; применяется также в команде проверки, где означает "не" |
" | Двойная кавычка: окаймляет символы и разрешает производить подстановку параметров |
' | Одинарная кавычка: окаймляет символы, но запрещает подстановку параметров |
\ | Обратная наклонная черта: экранирует одиночный символ, чтобы снять его специальное значение |
[] | Альтернативное использование для вызова команды проверки. Применяется также при генерации имен файлов, означая при этом диапазон символов |
@ | Соответствует каждому позиционному параметру командной строки |
>> | Дополнить стандартный вывод |
<< | Переназначить стандартный ввод на вводимые строки текста |
& | Используется как символ фонового процесса; соответствует также "файловому дескриптору", если используется в переадресации |
ВСТРОЕННЫЕ ОПЕРАТОРЫ ЯЗЫКА SHELL
Перечисленные ниже команды употребляются в программах на языке shell. Здесь имеется в виду System V Bourne shell.
В System V.2 - более новой версии System V - интерпретатор shell имеет некоторые дополнительные команды, перечисленные в отдельном списке.
Имеется также интерпретатор ksh (фактически это улучшенный Bourne shell), обладающий возможностями командных строк, характерными для csh (Си-shell). Интерпретатор ksh здесь не рассматривается.
ПРИМЕЧАНИЕ. Не позволяйте команде exec сбить вас с толку. Это не то же самое, что команда exec(2). Данная команда exec обрабатывается интерпретаторм shell, а exec(2) является системным вызовом.