Мендель Купер - Искусство программирования на языке сценариев командной оболочки
done
cd .. # ==> Подняться на один уровень вверх.
if [ "$deep" ] ; then # ==> Если depth = 0 (возвращает TRUE)...
swfi=1 # ==> выставить признак окончания поиска.
fi
deep=`expr $deep - 1` # ==> Уменьшить уровень вложенности.
}
# - Main -
if [ $# = 0 ] ; then
cd `pwd` # ==> Если аргумент командной строки отсутствует, то используется текущий каталог.
else
cd $1 # ==> иначе перейти в заданный каталог.
fi
echo "Начальный каталог = `pwd`"
swfi=0 # ==> Признак завершения поиска.
deep=0 # ==> Уровень вложенности.
numdirs=0
zz=0
while [ "$swfi" != 1 ] # Пока поиск не закончен...
do
search # ==> Вызвать функцию поиска.
done
echo "Всего каталогов = $numdirs"
exit 0
# ==> Попробуйте разобраться в том как этот сценарий работает.
Noah Friedman дал разрешение на публикацию своей библиотеки функций для работы со строками, которая, по сути, воспроизводит некоторые библиотечные функции языка C.
Пример A-20. Функции для работы со строками
#!/bin/bash
# string.bash --- эмуляция библиотеки функций string(3)
# Автор: Noah Friedman <[email protected]>
# ==> Используется с его разрешения.
# Дата создания: 1992-07-01
# Дата последней модификации: 1993-09-29
# Public domain
# Преобразование в синтаксис bash v2 выполнил Chet Ramey
# Комментарий:
# Код:
#:docstring strcat:
# Порядок использования: strcat s1 s2
#
# Strcat добавляет содержимое переменной s2 к переменной s1.
#
# Пример:
# a="foo"
# b="bar"
# strcat a b
# echo $a
# => foobar
#
#:end docstring:
###;;;autoload
function strcat ()
{
local s1_val s2_val
s1_val=${!1} # косвенная ссылка
s2_val=${!2}
eval "$1"='"${s1_val}${s2_val}"'
# ==> eval $1='${s1_val}${s2_val}' во избежание проблем,
# ==> если одна из переменных содержит одиночную кавычку.
}
#:docstring strncat:
# Порядок использования: strncat s1 s2 $n
#
# Аналог strcat, но добавляет не более n символов из
# переменной s2. Результат выводится на stdout.
#
# Пример:
# a=foo
# b=barbaz
# strncat a b 3
# echo $a
# => foobar
#
#:end docstring:
###;;;autoload
function strncat ()
{
local s1="$1"
local s2="$2"
local -i n="$3"
local s1_val s2_val
s1_val=${!s1} # ==> косвенная ссылка
s2_val=${!s2}
if [ ${#s2_val} -gt ${n} ]; then
s2_val=${s2_val:0:$n} # ==> выделение подстроки
fi
eval "$s1"='"${s1_val}${s2_val}"'
# ==> eval $1='${s1_val}${s2_val}' во избежание проблем,
# ==> если одна из переменных содержит одиночную кавычку.
}
#:docstring strcmp:
# Порядок использования: strcmp $s1 $s2
#
# Strcmp сравнивает две строки и возвращает число меньше, равно
# или больше нуля, в зависимости от результатов сравнения.
#:end docstring:
###;;;autoload
function strcmp ()
{
[ "$1" = "$2" ] && return 0
[ "${1}" '<' "${2}" ] > /dev/null && return -1
return 1
}
#:docstring strncmp:
# Порядок использования: strncmp $s1 $s2 $n
#
# Подобна strcmp, но сравнивает не более n символов
#:end docstring:
###;;;autoload
function strncmp ()
{
if [ -z "${3}" -o "${3}" -le "0" ]; then
return 0
fi
if [ ${3} -ge ${#1} -a ${3} -ge ${#2} ]; then
strcmp "$1" "$2"
return $?
else
s1=${1:0:$3}
s2=${2:0:$3}
strcmp $s1 $s2
return $?
fi
}
#:docstring strlen:
# Порядок использования: strlen s
#
# возвращает количество символов в строке s.
#:end docstring:
###;;;autoload
function strlen ()
{
eval echo "${#${1}}"
# ==> Возвращает длину переменной,
# ==> чье имя передается как аргумент.
}
#:docstring strspn:
# Порядок использования: strspn $s1 $s2
#
# Strspn возвращает максимальную длину сегмента в строке s1,
# который полностью состоит из символов строки s2.
#:end docstring:
###;;;autoload
function strspn ()
{
# Сброс содержимого переменной IFS позволяет обрабатывать пробелы как обычные символы.
local IFS=
local result="${1%%[!${2}]*}"
echo ${#result}
}
#:docstring strcspn:
# Порядок использования: strcspn $s1 $s2
#
# Strcspn возвращает максимальную длину сегмента в строке s1,
# который полностью не содержит символы из строки s2.
#:end docstring:
###;;;autoload
function strcspn ()
{
# Сброс содержимого переменной IFS позволяет обрабатывать пробелы как обычные символы.
local IFS=
local result="${1%%[${2}]*}"
echo ${#result}
}
#:docstring strstr:
# Порядок использования: strstr s1 s2
#
# Strstr выводит подстроку первого вхождения строки s2
# в строке s1, или ничего не выводит, если подстрока s2 в строке s1 не найдена.
# Если s2 содержит строку нулевой длины, то strstr выводит строку s1.
#:end docstring:
###;;;autoload
function strstr ()
{
# Если s2 -- строка нулевой длины, то вывести строку s1
[ ${#2} -eq 0 ] && { echo "$1" ; return 0; }
# не выводить ничего, если s2 не найдена в s1
case "$1" in
*$2*) ;;
*) return 1;;
esac
# использовать шаблон, для удаления всех несоответствий после s2 в s1
first=${1/$2*/}
# Затем удалить все несоответствия с начала строки
echo "${1##$first}"
}
#:docstring strtok:
# Порядок использования: strtok s1 s2
#
# Strtok рассматривает строку s1, как последовательность из 0, или более,
# лексем (токенов), разделенных символами строки s2
# При первом вызове (с непустым аргументом s1)
# выводит первую лексему на stdout.
# Функция запоминает свое положение в строке s1 от вызова к вызову,
# так что последующие вызовы должны производиться с пустым первым аргументом,
# чтобы продолжить выделение лексем из строки s1.
# После вывода последней лексемы, все последующие вызовы будут выводить на stdout
# пустое значение. Строка-разделитель может изменяться от вызова к вызову.
#:end docstring:
###;;;autoload
function strtok ()
{
:
}
#:docstring strtrunc:
# Порядок использования: strtrunc $n $s1 {$s2} {$...}
#
# Используется многими функциями, такими как strncmp, чтобы отсечь "лишние" символы.
# Выводит первые n символов в каждой из строк s1 s2 ... на stdout.
#:end docstring:
###;;;autoload
function strtrunc ()
{
n=$1 ; shift
for z; do
echo "${z:0:$n}"
done
}
# provide string
# string.bash конец библиотеки
# ========================================================================== #
# ==> Все, что находится ниже, добавлено автором документа.
# ==> Чтобы этот сценарий можно было использовать как "библиотеку", необходимо
# ==> удалить все, что находится ниже и "source" этот файл в вашем сценарии.
# strcat
string0=one
string1=two
echo
echo "Проверка функции "strcat" :"
echo "Изначально "string0" = $string0"
echo ""string1" = $string1"
strcat string0 string1
echo "Теперь "string0" = $string0"
echo
# strlen
echo
echo "Проверка функции "strlen" :"
str=123456789
echo ""str" = $str"
echo -n "Длина строки "str" = "
strlen str
echo
# Упражнение:
# ---------
# Добавьте проверку остальных функций.
exit 0
Michael Zick предоставил очень сложный пример работы с массивами и утилитой md5sum, используемой для кодирования сведений о каталоге.
От переводчика:
К своему стыду вынужден признаться, что перевод комментариев оказался мне не "по зубам", поэтому оставляю этот сценарий без перевода.
Пример A-21. Directory information
#! /bin/bash
# directory-info.sh
# Parses and lists directory information.
# NOTE: Change lines 273 and 353 per "README" file.
# Michael Zick is the author of this script.
# Used here with his permission.
# Controls
# If overridden by command arguments, they must be in the order:
# Arg1: "Descriptor Directory"
# Arg2: "Exclude Paths"
# Arg3: "Exclude Directories"
#
# Environment Settings override Defaults.
# Command arguments override Environment Settings.
# Default location for content addressed file descriptors.
MD5UCFS=${1:-${MD5UCFS:-'/tmpfs/ucfs'}}
# Directory paths never to list or enter
declare -a
EXCLUDE_PATHS=${2:-${EXCLUDE_PATHS:-'(/proc /dev /devfs /tmpfs)'}}
# Directories never to list or enter
declare -a
EXCLUDE_DIRS=${3:-${EXCLUDE_DIRS:-'(ucfs lost+found tmp wtmp)'}}
# Files never to list or enter
declare -a
EXCLUDE_FILES=${3:-${EXCLUDE_FILES:-'(core "Name with Spaces")'}}
# Here document used as a comment block.
: << LSfieldsDoc
# # # # # List Filesystem Directory Information # # # # #
#
# ListDirectory "FileGlob" "Field-Array-Name"
# or
# ListDirectory -of "FileGlob" "Field-Array-Filename"
# '-of' meaning 'output to filename'
# # # # #
String format description based on: ls (GNU fileutils) version 4.0.36
Produces a line (or more) formatted:
inode permissions hard-links owner group ...
32736 -rw------- 1 mszick mszick
size day month date hh:mm:ss year path
2756608 Sun Apr 20 08:53:06 2003 /home/mszick/core
Unless it is formatted:
inode permissions hard-links owner group ...
266705 crw-rw---- 1 root uucp
major minor day month date hh:mm:ss year path
4, 68 Sun Apr 20 09:27:33 2003 /dev/ttyS4
NOTE: that pesky comma after the major number
NOTE: the 'path' may be multiple fields:
/home/mszick/core
/proc/982/fd/0 -> /dev/null
/proc/982/fd/1 -> /home/mszick/.xsession-errors
/proc/982/fd/13 -> /tmp/tmpfZVVOCs (deleted)
/proc/982/fd/7 -> /tmp/kde-mszick/ksycoca
/proc/982/fd/8 -> socket:[11586]
/proc/982/fd/9 -> pipe:[11588]
If that isn't enough to keep your parser guessing,
either or both of the path components may be relative:
../Built-Shared -> Built-Static
../linux-2.4.20.tar.bz2 -> ../../../SRCS/linux-2.4.20.tar.bz2
The first character of the 11 (10?) character permissions field:
's' Socket
'd' Directory
'b' Block device
'c' Character device
'l' Symbolic link
NOTE: Hard links not marked - test for identical inode numbers
on identical filesystems.