9.1. Внутренние переменные


Встроенные переменные
$BASH

путь к исполняемому файлу Bash

  1. bash$ echo $BASH
  2. /bin/bash


$BASH_VERSINFO[n]

это массив, состоящий из 6 элементов, и содержащий информацию о версии Bash. Очень похожа на переменную $BASH_VERSION, описываемую ниже.

  1. # Информация о версии Bash:
  2. for n in 0 1 2 3 4 5
  3. do
  4.   echo "BASH_VERSINFO[$n] = ${BASH_VERSINFO[$n]}"
  5. done
  6. # BASH_VERSINFO[0] = 2                      # Major version no.
  7. # BASH_VERSINFO[1] = 05                     # Minor version no.
  8. # BASH_VERSINFO[2] = 8                      # Patch level.
  9. # BASH_VERSINFO[3] = 1                      # Build version.
  10. # BASH_VERSINFO[4] = release                # Release status.
  11. # BASH_VERSINFO[5] = i386-redhat-linux-gnu  # Architecture
  12.                                             # (same as $MACHTYPE).


$BASH_VERSION

версия Bash, установленного в системе

  1. bash$ echo $BASH_VERSION
  2. 2.04.12(1)-release
  3.        


  1. tcsh% echo $BASH_VERSION
  2. BASH_VERSION: Undefined variable.
  3.        


Проверка переменной $BASH_VERSION — неплохой метод проверки типа командной оболочки, под которой исполняется скрипт. Переменная $SHELL не всегда дает правильный ответ.

$DIRSTACK

содержимое вершины стека каталогов (который управляется командами pushd и popd)

Эта переменная соответствует команде dirs, за исключением того, что dirs показывает полное содержимое всего стека каталогов.

$EDITOR

заданный по-умолчанию редактор, вызываемый скриптом, обычно vi или emacs.

$EUID

"эффективный" идентификационный номер пользователя (Effective User ID)

Идентификационный номер пользователя, права которого были получены, возможно с помощью команды su.

Caution

Значение переменной $EUID необязательно должно совпадать с содержимым переменной $UID.

$FUNCNAME

имя текущей функции

  1. xyz23 ()
  2. {
  3.   echo "Исполняется функция $FUNCNAME."  # Исполняется функция xyz23.
  4. }
  5. xyz23
  6. echo "FUNCNAME = $FUNCNAME"        # FUNCNAME =
  7.                                    # Пустое (Null) значение за пределеми функций.


$GLOBIGNORE

Перечень шаблонных символов, которые будут проигнорированы при выполнении подстановки имен файлов (globbing) .

$GROUPS

группы, к которым принадлежит текущий пользователь

Это список групп (массив) идентификационных номеров групп для текущего пользователя, как эо записано в /etc/passwd.

  1. root# echo $GROUPS
  2. 0
  3. root# echo ${GROUPS[1]}
  4. 1
  5. root# echo ${GROUPS[5]}
  6. 6
  7.        


$HOME

домашний каталог пользователя, как правило это /home/username (см. Пример 9-13)

$HOSTNAME

Сетевое имя хоста устанавливается командой hostname во время исполнения инициализирующих сценариев на загрузке системы. Внутренняя переменная $HOSTNAME Bash получает свое значение посредством вызова функции gethostname(). См. так же Пример 9-13.

$HOSTTYPE

тип машины

Подобно $MACHTYPE, идентифицирует аппаратную архитектуру.

  1. bash$ echo $HOSTTYPE
  2. i686
$IFS

разделитель полей во вводимой строке (IFS — Internal Field Separator)

Эта переменная управляет порядком выделения полей (задает символы-разделители) при разборе строки символов.

По-умолчанию — пробельный символ (пробел, табуляция и перевод строки), но может быть изменен, например, для разбора строк, в которых отдельные поля разделены запятыми. Обратите внимание: при составлении содержимого переменной $*, Bash использует первый символ из $IFS для разделения аргументов. См. Пример 5-1.

  1. bash$ echo $IFS | cat -vte
  2. $
  3. bash$ bash -c 'set w x y z; IFS=":-;"; echo "$*"'
  4. w:x:y:z
  5.        


Caution

При всем при том следует помнить, что при использовании $IFS пробельные символы обрабатываются несколько иначе, чем все остальные.

Пример 9-1. $IFS и пробельные символы

  1. #!/bin/bash
  2. # При использовании $IFS, пробельные символы обрабатываются иначе, чем все остальные.
  3. output_args_one_per_line()
  4. {
  5.   for arg
  6.   do echo "[$arg]"
  7.   done
  8. }
  9. echo; echo "IFS=\" \""
  10. echo "-------"
  11. IFS=" "
  12. var=" a  b c   "
  13. output_args_one_per_line $var  # output_args_one_per_line `echo " a  b c   "`
  14. #
  15. # [a]
  16. # [b]
  17. # [c]
  18. echo; echo "IFS=:"
  19. echo "-----"
  20. IFS=:
  21. var=":a::b:c:::"               # То же самое, только пробелы заменены символом ":".
  22. output_args_one_per_line $var
  23. #
  24. # []
  25. # [a]
  26. # []
  27. # [b]
  28. # [c]
  29. # []
  30. # []
  31. # []
  32. # То же самое происходит и с разделителем полей "FS" в awk.
  33. # Спасибо Stephane Chazelas.
  34. echo
  35. exit 0


(Спасибо S. C., за разъяснения и примеры.)

$LC_COLLATE

Чаще всего устанавливается в .bashrc или /etc/profile, эта переменная задает порядок сортировки символов, в операциях подстановки имен файлов и в поиске по шаблону. При неверной настройке переменной LC_COLLATE можно получить весьма неожиданные результаты.

Note

Начиная с версии 2.05, Bash, в операциях подстановки имен файлов, не делает различий между символами верхнего и нижнего регистров, в диапазонах символов в квадратных скобках. Например,, ls [A-M]* выведет как File1.txt, так и file1.txt. Возврат к общепринятому стандарту поведения шаблонов в квадратных скобках выполняется установкой переменной LC_COLLATE в значение C командой export LC_COLLATE=C в файле /etc/profile и/или ~/.bashrc.

$LC_CTYPE

Эта внутренняя переменная определяет кодировку символов. Используется в операциях подстановки и поиске по шаблону.

$LINENO

Номер строки исполняемого сценария. Эта переменная имеет смысл только внутри исполняемого сценария и чаще всего применяется в отладочных целях.

  1. # *** BEGIN DEBUG BLOCK ***
  2. last_cmd_arg=$_  # Запомнить.
  3. echo "Строка $LINENO: переменная \"v1\" = $v1"
  4. echo "Последний аргумент командной строки = $last_cmd_arg"
  5. # *** END DEBUG BLOCK ***


$MACHTYPE

аппаратная архитектура

Идентификатор аппаратной архитектуры.

  1. bash$ echo $MACHTYPE
  2. i686
$OLDPWD

прежний рабочий каталог ("OLD-Print-Working-Directory")

$OSTYPE

тип операционной системы

  1. bash$ echo $OSTYPE
  2. linux
$PATH

путь поиска, как правило включает в себя каталоги /usr/bin/, /usr/X11R6/bin/, /usr/local/bin, и т.д.

Когда командный интерпретатор получает команду, то он автоматически пытается отыскать соответствующий исполняемый файл в указанном списке каталогов (в переменной $PATH). Каталоги, в указанном списке, должны отделяться друг от друга двоеточиями. Обычно, переменная $PATH инициализируется в /etc/profile и/или в ~/.bashrc (см. Глава 26).

  1. bash$ echo $PATH
  2. /bin:/usr/bin:/usr/local/bin:/usr/X11R6/bin:/sbin:/usr/sbin


Инструкция PATH=${PATH}:/opt/bin добавляет каталог /opt/bin в конец текущего пути поиска. Иногда может оказаться целесообразным, внутри сценария, временно добавить какой-либо каталог к пути поиска. По завершении работы скрипта, эти изменения будут утеряны (вспомните о том, что невозможно изменить переменные окружения вызывающего процесса).

Note

Текущий "рабочий каталог", ./, обычно не включается в $PATH из соображений безопасности.

$PIPESTATUS

Код возврата канала (конвейера). Интересно, что это не то же самое, что код возврата последней исполненной команды.

  1. bash$ echo $PIPESTATUS
  2. 0
  3. bash$ ls -al | bogus_command
  4. bash: bogus_command: command not found
  5. bash$ echo $PIPESTATUS
  6. 141
  7. bash$ ls -al | bogus_command
  8. bash: bogus_command: command not found
  9. bash$ echo $?
  10. 127
  11.        


Caution

Переменная $PIPESTATUS может давать неверные значения при вызове из командной строки.

  1. tcsh% bash
  2. bash$ who | grep nobody | sort
  3. bash$ echo ${PIPESTATUS[*]}
  4. 0
  5.        


Если поместить эти строки в сценарий и исполнить его, то будут выведены верные значения 0 1 0.

Спасибо Wayne Pollock за замечания и предоставленный пример.

$PPID

Переменная $PPID хранит PID (идентификатор) родительского процесса. [19]

Сравните с командой pidof.

$PROMPT_COMMAND

Переменная хранит команду, которая используется непосредственно для вывода первичного приглашения к вводу — $PS1.

$PS1

prompt, приглашение командной строки.

$PS2

Вторичное приглашение командной строки, выводится тогда, когда от пользователя ожидается дополнительный ввод. Отображается как ">".

$PS3

Третичное приглашение (prompt), выводится тогда, когда пользователь должен сделать выбор в операторе select (см. Пример 10-29).

$PS4

Приглашение (prompt) четвертого уровня, выводится в начале каждой строки вывода тогда, когда сценарий вызывается с ключом -x. Отображается как "+".

$PWD

рабочий (текущий) каталог

Аналог встроенной команды pwd.

  1. #!/bin/bash
  2. E_WRONG_DIRECTORY=73
  3. clear # Очистка экрана.
  4. TargetDirectory=/home/bozo/projects/GreatAmericanNovel
  5. cd $TargetDirectory
  6. echo "Удаление файлов в каталоге $TargetDirectory."
  7. if [ "$PWD" != "$TargetDirectory" ]
  8. then    # Защита от случайного удаления файлов не в том каталоге.
  9.   echo "Неверный каталог!"
  10.   echo "Переменная $PWD указывает на другой каталог!"
  11.   exit $E_WRONG_DIRECTORY
  12. fi
  13. rm -rf *
  14. rm .[A-Za-z0-9]*    # удалить "скрытые" файлы (начинающиеся с ".")
  15. # rm -f .[^.]* ..?*   удалить файлы, чьи имена начинаются с нескольких точек.
  16. # (shopt -s dotglob; rm -f *)   тоже работает верно.
  17. # Спасибо S.C. за замечание.
  18. # Имена файлов могут содержать любые символы из диапазона 0-255, за исключением "/".
  19. # Оставляю вопрос удаления файлов с "необычными" символами для самостоятельного изучения.
  20. # Здесь можно вставить дополнительные действия, по мере необходимости.
  21. echo
  22. echo "Конец."
  23. echo "Файлы, из каталога $TargetDirectory, удалены."
  24. echo
  25. exit 0


$REPLY

переменная по-умолчанию, куда записывается ввод пользователя, выполненный с помощью команды read если явно не задана другая переменная. Так же может использоваться в операторе select, для построения меню выбора.

  1. #!/bin/bash
  2. echo
  3. echo -n "Ваше любимое растение? "
  4. read
  5. echo "Ваше любимое растение: $REPLY."
  6. # REPLY хранит последнее значение, прочитанное командой "read" тогда, и только тогда
  7. #+ когда команде "read" не передается имя переменной.
  8. echo
  9. echo -n "Ваш любимый фрукт? "
  10. read fruit
  11. echo "Ваш любимый фрукт $fruit."
  12. echo "но..."
  13. echo "Значение переменной \$REPLY осталось равным $REPLY."
  14. # Переменная $REPLY не была перезаписана потому, что
  15. # следующей команде "read", в качестве аргумента была передана переменная $fruit
  16. echo
  17. exit 0


$SECONDS

Время паботы сценария в секундах.

  1. #!/bin/bash
  2. # Автор: Mendel Cooper
  3. # Дополнен переводчиком.
  4. #
  5. TIME_LIMIT=10
  6. INTERVAL=1
  7. echo
  8. echo "Для прерывания работы сценария, ранее чем через $TIME_LIMIT секунд, нажмите Control-C."
  9. echo
  10. while [ "$SECONDS" -le "$TIME_LIMIT" ]
  11. do
  12. # Оригинальный вариант сценария содержал следующие строки
  13. #  if [ "$SECONDS" -eq 1 ]
  14. #  then
  15. #    units=second
  16. #  else
  17. #    units=seconds
  18. #  fi
  19. #
  20. # Однако, из-за того, что в русском языке для описания множественного числа
  21. # существует большее число вариантов, чем в английском,
  22. # переводчик позволил себе смелость несколько подправить сценарий
  23. # (прошу ногами не бить! ;-) )
  24. # === НАЧАЛО БЛОКА ИЗМЕНЕНИЙ, ВНЕСЕННЫХ ПЕРЕВОДЧИКОМ ===
  25.   let "last_two_sym = $SECONDS - $SECONDS / 100 * 100" # десятки и единицы
  26.   if [ "$last_two_sym" -ge 11 -a "$last_two_sym" -le 19 ]
  27.   then
  28.     units="секунд"               # для чисел, которые заканчиваются на "...надцать"
  29.   else
  30.     let "last_sym = $last_two_sym - $last_two_sym / 10 * 10"  # единицы
  31.     case "$last_sym" in
  32.       "1" )
  33.         units="секунду"         # для чисел, заканчивающихся на 1
  34.       ;;
  35.       "2" | "3" | "4" )
  36.         units="секунды"         # для чисел, заканчивающихся на 2, 3 и 4
  37.       ;;
  38.       * )
  39.         units="секунд"          # для всех остальных (0, 5, 6, 7, 8, 9)
  40.       ;;
  41.     esac
  42.   fi
  43. # === КОНЕЦ БЛОКА ИЗМЕНЕНИЙ, ВНЕСЕННЫХ ПЕРЕВОДЧИКОМ ===
  44.   echo "Сценарий отработал $SECONDS $units."
  45.   #  В случае перегруженности системы, скрипт может перескакивать через отдельные
  46.   #+  значения счетчика
  47.   sleep $INTERVAL
  48. done
  49. echo -e "\a"  # Сигнал!
  50. exit 0


$SHELLOPTS

список допустимых опций интерпретатора shell. Переменная доступна только для чтения.

  1. bash$ echo $SHELLOPTS
  2. braceexpand:hashall:histexpand:monitor:history:interactive-comments:emacs
  3.        


$SHLVL

Уровень вложенности shell. Если в командной строке

  1. echo $SHLVL
дает 1, то в сценарии значение этой переменной будет больше на 1, т.е. 2.

$TMOUT

Если переменная окружения $TMOUT содержит ненулевое значение, то интерпретатор будет ожидать ввод не более чем заданное число секунд, что, в первичном приглашении (см. описание PS1 выше), может привести к автоматическому завершению сеанса работы.

Начиная с версии 2.05b Bash, стало возможным использование $TMOUT в сценариях в комбинации с read.

  1. # Работает только в сценариях Bash, начиная с версии 2.05b.
  2. TMOUT=3    # Ожидание ввода не более трех секунд.
  3. echo "Ваша любимая песня?"
  4. echo "Вводите быстрее, у Вас только $TMOUT секунды на обдумывние!"
  5. read song
  6. if [ -z "$song" ]
  7. then
  8.   song="(ответ не получен)"
  9.   # По-умолчанию.
  10. fi
  11. echo "Вам нравится $song."


Возможны и более сложные варианты организации организации ограничения времени ожидания ввода. Как один из вариантов, можно предложить организовать прерывание цикла ожидания по сигналу. Но это потребует написание функции обработки сигналов командой trap (см. Пример 29-5)

Пример 9-2. Ограничения времени ожидания ввода

  1. #!/bin/bash
  2. # timed-input.sh
  3. # TMOUT=3            бесполезно в сценариях
  4. TIMELIMIT=3  # Три секунды в данном случае, но может быть установлено и другое значение
  5. PrintAnswer()
  6. {
  7.   if [ "$answer" = TIMEOUT ]
  8.   then
  9.     echo $answer
  10.   else       # Чтобы не спутать разные варианты вывода.
  11.     echo "Ваше любимое растение $answer"
  12.     kill $!  # "Прибить" ненужную больше функцию TimerOn, запущенную в фоновом процессе.
  13.              # $! — PID последнего процесса, запущенного в фоне.
  14.   fi
  15. }
  16. TimerOn()
  17. {
  18.   sleep $TIMELIMIT && kill -s 14 $$ &
  19.   # Ждать 3 секунды, после чего выдать sigalarm сценарию.
  20. }
  21. Int14Vector()
  22. {
  23.   answer="TIMEOUT"
  24.   PrintAnswer
  25.   exit 14
  26. }
  27. trap Int14Vector 14   # переназначить процедуру обработки прерывания от таймера (14)
  28. echo "Ваше любимое растение? "
  29. TimerOn
  30. read answer
  31. PrintAnswer
  32. #  По общему признанию, это не очень хороший способ ограничения времени ожидания,
  33. #+ однако опция "-t"команды "read" упрощает задачу.
  34. #  См. "t-out.sh", ниже.
  35. #  Если вам нужно что-то более элегантное...
  36. #+ подумайте о написании программы на C или C++,
  37. #+ с использованием соответствующих библиотечных функций, таких как 'alarm' и 'setitimer'.
  38. exit 0

В качестве альтернативы можно использовать stty.

Пример 9-3. Еще один пример ограничения времени ожидания ввода от пользователя

  1. #!/bin/bash
  2. # timeout.sh
  3. # Автор: Stephane Chazelas,
  4. # дополнен автором документа.
  5. INTERVAL=5                # предел времени ожидания
  6. timedout_read() {
  7.   timeout=$1
  8.   varname=$2
  9.   old_tty_settings=`stty -g`
  10.   stty -icanon min 0 time ${timeout}0
  11.   eval read $varname      # или просто    read $varname
  12.   stty "$old_tty_settings"
  13.   # См. man stty.
  14. }
  15. echo; echo -n "Как Вас зовут? Отвечайте быстрее! "
  16. timedout_read $INTERVAL your_name
  17. # Такой прием может не работать на некоторых типах терминалов.
  18. # Максимальное время ожидания зависит от терминала.
  19. # (чаще всего это 25.5 секунд).
  20. echo
  21. if [ ! -z "$your_name" ]  # Если имя было введено...
  22. then
  23.   echo "Вас зовут $your_name."
  24. else
  25.   echo "Вы не успели ответить."
  26. fi
  27. echo
  28. # Алгоритм работы этого сценария отличается от "timed-input.sh".
  29. # Каждое нажатие на клавишу вызывает сброс счетчика в начальное состояние.
  30. exit 0

Возможно самый простой способ — использовать опцию -t команды read.

Пример 9-4. Ограничение времени ожидания команды read

  1. #!/bin/bash
  2. # t-out.sh
  3. TIMELIMIT=4        # 4 секунды
  4. read -t $TIMELIMIT variable <&1
  5. echo
  6. if [ -z "$variable" ]
  7. then
  8.   echo "Время ожидания истекло."
  9. else
  10.   echo "variable = $variable"
  11. fi  
  12. exit 0
$UID

user id number

UID (идентификатор) текущего пользователя, в соответствии с /etc/passwd

Это реальный UID текущего пользователя, даже если он временно приобрел права другого пользователя с помощью su. Переменная $UID доступна только для чтения.

Пример 9-5. Я — root?

  1. #!/bin/bash
  2. # am-i-root.sh:   Root я, или не root?
  3. ROOT_UID=0   # $UID root-а всегда равен 0.
  4. if [ "$UID" -eq "$ROOT_UID" ]  # Настоящий "root"?
  5. then
  6.   echo "- root!"
  7. else
  8.   echo "простой пользователь (но мамочка вас тоже любит)!"
  9. fi
  10. exit 0
  11. # ============================================================= #
  12. #  Код, приведенный ниже, никогда не отработает,
  13. #+ поскольку работа сценария уже завершилась выше
  14. # Еще один способ отличить root-а от не root-а:
  15. ROOTUSER_NAME=root
  16. username=`id -nu`              # Или...   username=`whoami`
  17. if [ "$username" = "$ROOTUSER_NAME" ]
  18. then
  19.   echo "Рутти-тутти. - root!"
  20. else
  21.   echo "Вы - лишь обычный юзер."
  22. fi

См. также Пример 2-2.

Note

Переменные $ENV, $LOGNAME, $MAIL, $TERM, $USER и $USERNAME, не являются встроенными переменными Bash. Тем не менее, они часто инициализируются как переменные окружения в одном из стартовых файлов Bash. Переменная $SHELL, командная оболочка пользователя, может задаваться в /etc/passwd или в сценарии "init" и она тоже не является встроенной переменной Bash.

  1. tcsh% echo $LOGNAME
  2. bozo
  3. tcsh% echo $SHELL
  4. /bin/tcsh
  5. tcsh% echo $TERM
  6. rxvt
  7. bash$ echo $LOGNAME
  8. bozo
  9. bash$ echo $SHELL
  10. /bin/tcsh
  11. bash$ echo $TERM
  12. rxvt
  13.        


Позиционные параметры (аргументы)

$0, $1, $2 и т.д.

аргументы передаются... из командной строки в сценарий, функциям или команде set (см. Пример 4-5 и Пример 11-14)

$#

количество аргументов командной строки [20], или позиционных параметров (см. Пример 33-2)

$*

Все аргументы (позиционные параметры), в виде одной строки (слова)

Note

"$*" — необходимо заключать в кавычки.

$@

То же самое, что и $*, но при этом каждый параметр представлен как отдельная строка (слово), т.е. параметры не подвергаются какой либо интерпретации.

Note

"$@" — необходимо заключать в кавычки.

Пример 9-6. arglist: Вывод списка аргументов с помощью переменных $* и $@

  1. #!/bin/bash
  2. # Вызовите сценарий с несколькими аргументами, например: "один два три".
  3. E_BADARGS=65
  4. if [ ! -n "$1" ]
  5. then
  6.   echo "Порядок использования: `basename $0` argument1 argument2 и т.д."
  7.   exit $E_BADARGS
  8. fi
  9. echo
  10. index=1
  11. echo "Список аргументов в переменной \"\$*\":"
  12. for arg in "$*"  # Работает некорректно, если "$*" не ограничена кавычками.
  13. do
  14.   echo "Аргумент #$index = $arg"
  15.   let "index+=1"
  16. done             # $* воспринимает все аргументы как одну строку.
  17. echo "Полный список аргументов выглядит как одна строка."
  18. echo
  19. index=1
  20. echo "Список аргументов в переменной \"\$@\":"
  21. for arg in "$@"
  22. do
  23.   echo "Аргумент #$index = $arg"
  24.   let "index+=1"
  25. done             # $@ воспринимает аргументы как отдельные строки (слова).
  26. echo "Список аргументов выглядит как набор различных строк (слов)."
  27. echo
  28. exit 0

После команды shift (сдвиг), первый аргумент, в переменной $@, теряется, а остальные сдвигаются на одну позицию "вниз" (или "влево", если хотите).

  1. #!/bin/bash
  2. # Вызовите сценарий в таком виде: ./scriptname 1 2 3 4 5
  3. echo "$@"    # 1 2 3 4 5
  4. shift
  5. echo "$@"    # 2 3 4 5
  6. shift
  7. echo "$@"    # 3 4 5
  8. # Каждая из команд "shift" приводит к потере аргумента $1,
  9. # но остальные аргументы остаются в "$@".


Специальная переменная $@ может быть использована для выбора типа ввода в сценария. Команда cat "$@" позволяет выполнять ввод как со стандартного устройства ввода stdin, так и из файла, имя которого передается сценарию из командной строки. См. Пример 12-20 и Пример 12-21.

Caution

Переменные $* и $@, в отдельных случаях, могут содержать противоречивую информацию! Это зависит от содержимого переменной $IFS.

Пример 9-7. Противоречия в переменных $* и $@

  1. #!/bin/bash
  2. #  Демонстрация противоречивости содержимого внутренних переменных "$*" и "$@",
  3. #+ которая проявляется при изменении порядка заключения параметров в кавычки.
  4. #  Демонстрация противоречивости, проявляющейся при изменении
  5. #+ содержимого переменной IFS.
  6. set"Первый один" "второй" "третий:один" "" "Пятый: :один"
  7. # Установка аргументов $1, $2, и т.д.
  8. echo
  9. echo 'IFS по-умолчанию, переменная "$*"'
  10. c=0
  11. for i in "$*"               # в кавычках
  12. do echo "$((c+=1)): [$i]"   # Эта строка остается без изменений во всех циклах.
  13.                             # Вывод аргументов.
  14. done
  15. echo ---
  16. echo 'IFS по-умолчанию, переменная $*'
  17. c=0
  18. for i in $*                 # без кавычек
  19. do echo "$((c+=1)): [$i]"
  20. done
  21. echo ---
  22. echo 'IFS по-умолчанию, переменная "$@"'
  23. c=0
  24. for i in "$@"
  25. do echo "$((c+=1)): [$i]"
  26. done
  27. echo ---
  28. echo 'IFS по-умолчанию, переменная $@'
  29. c=0
  30. for i in $@
  31. do echo "$((c+=1)): [$i]"
  32. done
  33. echo ---
  34. IFS=:
  35. echo 'IFS=":", переменная "$*"'
  36. c=0
  37. for i in "$*"
  38. do echo "$((c+=1)): [$i]"
  39. done
  40. echo ---
  41. echo 'IFS=":", переменная $*'
  42. c=0
  43. for i in $*
  44. do echo "$((c+=1)): [$i]"
  45. done
  46. echo ---
  47. var=$*
  48. echo 'IFS=":", переменная "$var" (var=$*)'
  49. c=0
  50. for i in "$var"
  51. do echo "$((c+=1)): [$i]"
  52. done
  53. echo ---
  54. echo 'IFS=":", переменная $var (var=$*)'
  55. c=0
  56. for i in $var
  57. do echo "$((c+=1)): [$i]"
  58. done
  59. echo ---
  60. var="$*"
  61. echo 'IFS=":", переменная $var (var="$*")'
  62. c=0
  63. for i in $var
  64. do echo "$((c+=1)): [$i]"
  65. done
  66. echo ---
  67. echo 'IFS=":", переменная "$var" (var="$*")'
  68. c=0
  69. for i in "$var"
  70. do echo "$((c+=1)): [$i]"
  71. done
  72. echo ---
  73. echo 'IFS=":", переменная "$@"'
  74. c=0
  75. for i in "$@"
  76. do echo "$((c+=1)): [$i]"
  77. done
  78. echo ---
  79. echo 'IFS=":", переменная $@'
  80. c=0
  81. for i in $@
  82. do echo "$((c+=1)): [$i]"
  83. done
  84. echo ---
  85. var=$@
  86. echo 'IFS=":", переменная $var (var=$@)'
  87. c=0
  88. for i in $var
  89. do echo "$((c+=1)): [$i]"
  90. done
  91. echo ---
  92. echo 'IFS=":", переменная "$var" (var=$@)'
  93. c=0
  94. for i in "$var"
  95. do echo "$((c+=1)): [$i]"
  96. done
  97. echo ---
  98. var="$@"
  99. echo 'IFS=":", переменная "$var" (var="$@")'
  100. c=0
  101. for i in "$var"
  102. do echo "$((c+=1)): [$i]"
  103. done
  104. echo ---
  105. echo 'IFS=":", переменная $var (var="$@")'
  106. c=0
  107. for i in $var
  108. do echo "$((c+=1)): [$i]"
  109. done
  110. echo
  111. # Попробуйте запустить этот сценарий под ksh или zsh -y.
  112. exit 0
  113. # Это сценарий написан Stephane Chazelas,
  114. # Незначительные изменения внесены автором документа.
Note

Различия между $@ и $* наблюдаются только тогда, когда они помещаются в двойные кавычки.

Пример 9-8. Содержимое $* и $@, когда переменная $IFS — пуста

  1. #!/bin/bash
  2. # Если переменная $IFS инициализирована "пустым" значением,
  3. # то "$*" и "$@" содержат аргументы не в том виде, в каком ожидается.
  4. mecho ()       # Вывод аргументов.
  5. {
  6. echo "$1,$2,$3";
  7. }
  8. IFS=""         # Инициализация "пустым" значением.
  9. set a b c      # Установка аргументов.
  10. mecho "$*"     # abc,,
  11. mecho $*       # a,b,c
  12. mecho $@       # a,b,c
  13. mecho "$@"     # a,b,c
  14. # Поведение переменных $* и $@, при "пустой" $IFS, зависит
  15. # от версии командной оболочки, Bash или sh.
  16. # Поэтому, было бы неразумным пользоваться этой "фичей" в своих сценариях.
  17. # Спасибо S.C.
  18. exit 0

Прочие специальные переменные

$-

Список флагов, переданных сценарию (командой set). См. Пример 11-14.

Caution

Эта конструкция изначально была введена в ksh, откуда перекочевала в Bash и, похоже, работает в Bash не совсем надежно. Единственное возможное применение — проверка - запущен ли сценарий в интерактивном режиме.

$!

PID последнего, запущенного в фоне, процесса

  1. LOG=$0.log
  2. COMMAND1="sleep 100"
  3. echo "Запись в лог всех PID фоновых процессов, запущенных из сценария: $0" >> "$LOG"
  4. # Таким образом возможен мониторинг и удаление процессов по мере необходимости.
  5. echo >> "$LOG"
  6. # Команды записи в лог.
  7. echo -n "PID of \"$COMMAND1\":  " >> "$LOG"
  8. ${COMMAND1} &
  9. echo $! >> "$LOG"
  10. # PID процесса "sleep 100":  1506
  11. # Спасибо Jacques Lederer за предложенный пример.


$_

Специальная переменная, содержит последний аргумент предыдущей команды.

Пример 9-9. Переменная "подчеркивание"

  1. #!/bin/bash
  2. echo $_              # /bin/bash
  3.                      # Для запуска сценария был вызван /bin/bash.
  4. du >/dev/null        # Подавление вывода.
  5. echo $_              # du
  6. ls -al >/dev/null    # Подавление вывода.
  7. echo $_              # -al  (последний аргумент)
  8. :
  9. echo $_              # :
$?

Код возврата команды, функции или скрипта (см. Пример 22-6)

$$

PID самого процесса-сценария. Переменная $$ часто используется при генерации "уникальных" имен для временных файлов (см. Пример A-14, Пример 29-6, Пример 12-26 и Пример 11-24). Обычно это проще чем вызов mktemp.


[19]    PID текущего процесса хранится в переменной $$.

[20]    Слова "аргумент" и "параметр" очень часто используются как синонимы. В тексте данного документа, они применяются для обозначения одного и того же понятия, будь то аргумент, передаваемый скрипту из командной строки или входной параметр функции.