Описание: Кандидат BSDA должен свободно пользоваться оболочками sh(1), csh(1) или tcsh(1). Кандидат должен уметь изменять поведение обеих оболочек временно или постоянно, включая: предотвращать уничтожение существующих файлов, использовать историю команд, определять псевдонимы команд для экономии времени в командной строке. Кандидат должен знать как временно отменить псевдоним.
Практика:
sh(1), csh(1) и tcsh(1), включая !
,
!!
, $
, 0
,
h
, t
, r
,
p
, \
.
В системах BSD поставляется две оболочки, наличие которых требуется стандартом POSIX: sh(1) и csh(1). Первая традичионно используется для написания сценариев. Вторая больше приспособлена для работы в интерактивном режиме. Конечно ничто не мешает вам установить у себя bash(1) или другую, более или менее «продвинутую» оболочку, однако в нашем курсе мы изучаем только штатные средства BSD, и на то есть свои основания (см. Раздел 7.7.2, «Почему sh(1)?»).
Поскольку данный раздел посвящён интерактивной работе с оболочками, мы будем описывать в нём почти исключительно csh(1). Полное описание данной оболочки, на русском языке, доступно здесь: [url://csh-1998].
С другой стороны, я отдаю себе полный отчёт в том, насколько популярна оболочка bash(1) среди системных администраторов, поэтому иногда буду делать реверансы в её сторону в стиле «... а в bash(1) тоже есть подобная функция, она делатся так: ...». Кроме того, в случае если некая упоминаемая возможность есть и в bash(1) и в sh(1) я буду делать реверансы в пользу sh(1), хотя последний крайне неудачен с точки зрения интерактивной работы.
Важно | |
---|---|
csh(1) по умолчанию является оболочкой
пользователя root. Никогда не меняйте её на
bash(1) или любую другую оболочку из иерархии
/usr/local ! От пользователя root требуются
некоторые действия в критические моменты жизнедеятельности системы,
когда иерархия /usr несмонтирована. Поэтому
уметь работать в csh(1) может быть жизненно
важно.
|
Для этой цели в оболочках существует режим
«noclobber». В csh(1) он включается
путём задания переменной окружения noclobber
.
%
touch test%
set noclobber=1%
echo hello > test test: Файл существует.%
unset noclobber%
echo hello > test
В sh(1) этот режим можно включить используя
аргумент командной строки -C. Таким образом, можно использовать
shebang #!/bin/sh -C
.
Существует ряд отличий между оболочками с точки зрения языка. Язык csh(1) сделан более C-подобным. Изменения довольно глубоки, в частности csh(1) трактует 1 как истину, а 0 как ложь, в отличие от sh(1), поэтому он преобразует на лету коды возврата программ 0 к 1, а всё, что больше 0 к нулю. В csh(1) иной синтаксис написания циклов и других конструкций, больше типов данных. Так в csh(1) поддерживаются массивы (массивы поддерживаются и в bash(1)).
csh(1) поддерживает работу с историей команд и completion. (К стыду своему не знаю как это будет по-русски, имеется ввиду явление когда имена файлов дописываются при нажатии клавиши <TAB>). Ни то, ни другое не поддерживается в sh(1) (но поддерживается в bash(1)).
Если в переменной в csh(1) содержится имя файла, то с ним можно работать используя различные модификаторы:
%
set name=/home/emin/BSDCert/BSDCert.xml%
echo $name /home/emin/BSDCert/BSDCert.xml%
echo $name:h /home/emin/BSDCert%
echo $name:t BSDCert.xml%
echo $name:e xml%
echo $name:h:h /home/emin%
set names=(/home/emin/BSDCert/*)%
echo $names /home/emin/BSDCert/BSDCert.xml /home/emin/BSDCert/Makefile /home/emin/BSDCert/de fault.css /home/emin/BSDCert/index.shtml /home/emin/BSDCert/macro.vim /home/emin /BSDCert/single.xsl /home/emin/BSDCert/split.xsl%
echo $names[1] /home/emin/BSDCert/BSDCert.xml%
echo $names[1]:h /home/emin/BSDCert%
echo $names[1]:t BSDCert.xml%
echo $names:h /home/emin/BSDCert /home/emin/BSDCert/Makefile /home/emin/BSDCert/default.css /h ome/emin/BSDCert/index.shtml /home/emin/BSDCert/macro.vim /home/emin/BSDCert/sin gle.xsl /home/emin/BSDCert/split.xsl%
echo $names:gh /home/emin/BSDCert /home/emin/BSDCert /home/emin/BSDCert /home/emin/BSDCert /hom e/emin/BSDCert /home/emin/BSDCert /home/emin/BSDCert%
echo $names:gt BSDCert.xml Makefile default.css index.shtml macro.vim single.xsl split.xsl%
echo $names:ge xml css shtml vim xsl xsl
Похожие фокусы возможны, впрочем, и в sh(1) (правда в нём нет массивов):
$
name=/home/emin/BSDCert/BSDCert.xml$
echo $name /home/emin/BSDCert/BSDCert.xml$
echo ${name%/*} /home/emin/BSDCert$
echo ${name##*/} BSDCert.xml$
echo ${name##*.} xml
Впрочем, последний пример явно потерпит фиаско, если в имени файла расширения не будет, и, что ещё хуже, если в имени файла его не будет, а в имени каталога, в котором он находится, оно будет.
Таблица 7.11. Модификаторы переменных в csh(1)
Модификатор | Описание |
---|---|
h | Удалить имя файла, сохранив компоненты пути (то есть удалить в слове текст справа до ближайшего символа /). От слова head. |
gh | Применить модификатор h глобально ко всем элементам массива |
r | Удалить расширение файла, указанное через точку, и саму точку |
gr | Применить модификатор r глобально ко всем элементам массива |
e | Удалить имя файла вместе с точкой, сохранив расширение имени |
ge | Применить модификатор e глобально ко всем элементам массива |
t | Сохранить имя файла, удалив компоненты пути (то есть удалить текст слева от самого правого символа / и сам этот символ). От слова «tail». |
gt | Применить модификатор t глобально ко всем элементам массива |
q | Запретить дальнейшую модификацию слова. Слово заключается в кавычки |
x | Разбить на слова по разделителям и запретить дальнейшую модификацию. Результат заключается в кавычки. |
Для просмотра истории команд служит встроенная команда history:
%
history
1 14:27 set name=/home/emin/BSDCert/BSDCert.xml
2 14:28 echo $name
3 14:28 echo $name:h
4 14:28 echo $name:t
5 14:28 echo $name:e
6 14:28 echo $name:h:h
7 14:29 set names= ( /home/emin/BSDCert/* )
8 14:29 echo $names[1]
9 14:29 echo $names[1]:h
10 14:30 echo $names[1]:t
11 14:30 echo $names:h
12 14:30 echo $names:gh
13 14:30 echo $names:gt
14 14:30 echo $names:ge
При помощи символа !
можно выполнить
некоторые действия из истории, например:
%
!1 set name=/home/emin/BSDCert/BSDCert.xml%
!7 set names= ( /home/emin/BSDCert/* )%
!?his? history 1 14:27 set name=/home/emin/BSDCert/BSDCert.xml 2 14:28 echo $name 3 14:28 echo $name:h 4 14:28 echo $name:t 5 14:28 echo $name:e 6 14:28 echo $name:h:h 7 14:29 set names= ( /home/emin/BSDCert/* ) 8 14:29 echo $names[1] 9 14:29 echo $names[1]:h 10 14:30 echo $names[1]:t 11 14:30 echo $names:h 12 14:30 echo $names:gh 13 14:30 echo $names:gt 14 14:30 echo $names:ge 15 15:30 history 16 15:31 set name=/home/emin/BSDCert/BSDCert.xml 17 15:31 set names= ( /home/emin/BSDCert/* ) 18 15:31 history%
-2 set names= ( /home/emin/BSDCert/* )%
!! set names= ( /home/emin/BSDCert/* )%
!e echo $names:ge xml css shtml vim xsl xsl
Разберём чуть более сложный пример:
%
touch abc cba%
cat !!* cat abc cba%
echo 'aaa\?
bbb\?
ccc' > abc%
echo 'aaa\?
bcb\?
ccc'> cba%
diff !t* diff abc cba 2c2 < bbb --- > bcb%
echo !t:0 echo touch touch%
echo !t:1 !t:2 echo abc cba abc cba%
echo !?ab?% echo abc abc%
echo !t^ !t$ echo abc cba abc cba
Разрешается не ставить двоеточие перед знаками
*
, ^
, $
,
-
и %
В работе с историей команд можно использовать модификаторы. Некоторые модификаторы были рассмотрены выше, есть и специфические модификаторы, которые применяются только здесь:
p
&
s/pattern/subst/
Пусть после выполнения команды history на экран дисплея выведено:
%
history
1 cat /home/ivanov/file1.c
2 cc pa1.c pa2.c pa3.c pa4.c >& errors &
...
Тогда следующие команды приведут к следующим действиям:
!1:0 !1^:t:r
cat
. Затем первое слово первой
строки (/home/ivanov/file1.c
),
к которому будет последовательно применено два
модификатора: :t
и :r
, в
результате останется file1
.
Итого, получаем команду cat
file1
.
!1:0 !1^:h/document
cat
/home/ivanov/document
.
!1:0 !1^:h:s?ivanov?sidorov?/document
cat /home/sidorov/document
!1:0 !1^:h:s?ivanov?sidorov?/doc !1^:&:p
cat /home/sidorov/doc
/home/sidorov/file1.c
. Здесь модификатор
&
заставляет повторить предыдущую
замену, а модификатор :p
заставляет
просто напечатать результат на экране, вместо того, чтобы
выполнить действие.
!1:0 !2:1-4:gs?pa?ff?:p
g
) делается замена
pa
на ff
, результат печатается:
cat ff1.c ff2.c ff3.c ff4.c
Существует способ редактирования последней командной строки:
%
echo abc cba abc cba%
^abc^cba^ echo cba cba cba cba
Представьте себе, что у вас определён следующий псевдоним:
%
alias sp "sort \!* | print"
Теперь команды sp one two
и sort one two | print
тождественны, так
как в !*
будут подставлены аргументы, с
которыми вызвана команда sp
.