Основы сценария оболочки

Запись сценария оболочки походит на поездку на велосипеде. Вы уменьшаетесь и очищаете колени много сначала. С немного большим опытом Вы становитесь удобной поездкой на них вокруг города, но также и быстро обнаруживаете, почему большинство людей управляет автомобилями для более длинных прохождений.

Сценарии Shell обычно считаются языком связующего звена, идеалом для создания маленьких частей кода, подключающих другие инструменты вместе. В то время как сценарии оболочки могут использоваться для более сложных задач, они обычно - не лучший выбор.

Если у Вас есть когда-нибудь успешно trued велосипедное колесо (или оплатил кому-то еще, чтобы сделать так), это подобно изучению основ сценариев оболочки. Если Вы не делаете истины Ваши сценарии, они колеблются. Другими словами часто просто записать сценарий, но это может быть более сложно для записи сценария, последовательно работающего хорошо.

Эта глава и следующие две главы представляют фундаментальные понятия сценариев оболочки. Остающиеся главы в этом документе обеспечивают дополнительную ширину и глубину. Этот документ не предназначается, чтобы быть полной ссылкой при записи сценариев оболочки, и при этом это не могло быть. Это действительно, однако, предоставляет хорошую начальную точку новичкам, сначала изучающим эту черную магию.

Диалекты сценария оболочки

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

С этой целью первый урок, который необходимо извлечь прежде, чем записать сценарий оболочки, - то, что существует два существенно различных набора синтаксиса сценария оболочки: синтаксис Оболочки Bourne и синтаксис оболочки C. Синтаксис оболочки C более удобен для многих программистов C, потому что синтаксис несколько подобен. Однако синтаксис Оболочки Bourne значительно более гибок и таким образом более широко используется. Поэтому этот документ только касается синтаксиса Оболочки Bourne.

Второй тяжелый урок, который Вы неизменно извлечете, - то, что каждый диалект синтаксиса Оболочки Bourne отличается немного. Этот документ включает только чистый синтаксис Оболочки Bourne и несколько СПЕЦИФИЧНЫХ ДЛЯ BASH расширений. Где СПЕЦИФИЧНЫЙ ДЛЯ BASH синтаксис используется, он ясно отмечен.

Терминология и тонкие синтаксические различия могут сбить с толку — даже немного подавляющий время от времени; имел Дороти в Мастере Оза, программист, Вы, возможно, услышали, что она воскликнула, «BASH и ZSH и CSH, О Мой!» К счастью, как только Вы получаете основы, вещи обычно встают на свое место, пока Вы избегаете использования специфичных для оболочки функций. Останьтесь на узкой дороге, и Ваш код будет переносимым.

Некоторые общие оболочки упоминаются ниже, группируются синтаксисом сценария:

Совместимые с границей оболочки

Совместимые с оболочкой C оболочки

Многие из этих оболочек имеют больше чем одно изменение. Большинство этих изменений обозначено путем добавления префикса имени существующей оболочки с дополнительными буквами, которые коротки для того, что дифференцирует их от исходной оболочки. Например:

И т.д. В целом, за исключением csh и tcsh, обычно безопасно предположить, что любая современная оболочка входа в систему совместима с синтаксисом Оболочки Bourne.

Она продает оболочки C

Оболочка C популярна среди некоторых пользователей как оболочка для взаимодействия с компьютером, потому что это позволяет простым сценариям быть записанными более легко. Однако язык сценариев оболочки C ограничивается многими способами, многие из которых тверды работать вокруг. Поэтому использование языка сценариев оболочки C для записи сложных сценариев не рекомендуется. Для получения дополнительной информации читайте “CSH Программирование Продуманного Вредный” в http://www .faqs.org/faqs/unix-faq/shell/csh-whynot/. Несмотря на то, что многие дефекты языка, которые это описывает, фиксируются некоторыми современными оболочками C, если Вы запишете сценарий, который должен работать над многократными компьютерами через различные операционные системы, то Вы не можете всегда гарантировать, что установленная оболочка C будет поддерживать те расширения.

Однако язык сценариев оболочки C имеет свое использование, особенно для записи сценариев, устанавливающих переменные окружения для интерактивных сред оболочки, выполняющих ряд команд в порядке или выполняющих другую относительно легкую работу по дому. Для поддержки такого использования синтаксис оболочки C представлен рядом с синтаксисом Оболочки Bourne в этой главе "основ”, если это возможно.

За пределами этой главы этот документ обычно не касается синтаксиса оболочки C. Если после чтения этого, Вы все еще хотите записать более сложный сценарий с помощью языка программирования оболочки C, можно найти больше информации в на оболочке C в странице руководства для csh.

Переменные Shell и печать

То, что следует, является очень основным сценарием оболочки, распечатывающим “Привет, мир!” на экран:

#!/bin/sh
 
echo "Hello, world!"

Первая вещь, которую необходимо заметить, состоит в том, что сценарий запускается с‘#!’. Это известно как строка интерпретатора. Если Вы не указываете строку интерпретатора, значением по умолчанию обычно является Оболочка Bourne (/bin/sh). Однако лучше указывать эту строку так или иначе для непротиворечивости.

Вторая вещь, которую необходимо заметить, echo команда. echo команда почти универсальна в оболочке, пишущей сценарий как средние значения для печати чего-то на экран пользователя. (С технической точки зрения, echo обычно встроенная оболочка, но она также существует как как автономная команда, /bin/echo. Можно считать больше о различии между встроенной версией и автономной версией в эхе и Использовании Shell Builtins Везде, где Возможно.)

Если Вы хотели бы, можно попробовать этот сценарий путем сохранения тех строк в текстовом файле (скажите «hello_world.sh») в корневом каталоге. Затем в Терминале введите:

chmod u+x hello_world.sh
./hello_world.sh

Конечно, этот сценарий не особенно полезен. Это просто распечатывает слова “Привет, мир! “на Ваш экран. Для создания этого более интересным следующий сценарий добавляет несколько переменных.

#!/bin/sh
 
FIRST_ARGUMENT="$1"
echo "Hello, world $FIRST_ARGUMENT!"

Введите или вставьте этот сценарий в текстовый редактор по Вашему выбору (см. Текстовые файлы Создания в Своем Корневом каталоге для справки, создающей текстовый файл), и сохраните файл в своем корневом каталоге в вызванном файле test.sh.

Как только Вы сохранили файл в своем корневом каталоге, введите‘chmod a+x test.sh’в Терминале для создания его исполнимой программой. Наконец, выполните его с‘./test.sh leaders’. Необходимо видеть “Привет, мировые лидеры!” распечатал на Ваш экран.

Этот сценарий обеспечивает пример переменного присвоения. Переменная $1 содержит первый параметр, переданный сценарию оболочки. В этом примере сценарий делает копию и хранит его в вызванную переменную FIRST_ARGUMENT, тогда печать та переменная.

Необходимо сразу заметить, что переменные могут или могут не начаться со знака доллара, в зависимости от того, как Вы используете их. Если Вы хотите разыменовать переменную, Вы предшествуете ей со знаком доллара. Оболочка тогда вставляет содержание переменной в той точке в сценарии. Для всего другого использования Вы не предшествуете ему со знаком доллара.

Необходимо также заметить, что параметр эху окружается двойными кавычками. Это объяснено далее в следующем разделе, Используя Параметры И Переменные, Содержащие Пробелы.

Используя параметры и переменные, содержащие пробелы

Бросьте второй взгляд на сценарий от предыдущего раздела:

#!/bin/sh
 
FIRST_ARGUMENT="$1"
echo "Hello, world $FIRST_ARGUMENT!"

Заметьте, что оператор эха сопровождается строкой, окруженной кавычками. Обычно, оболочка использует пробелы для разделения параметров командам. За пределами кавычек оболочка обработала бы «Привет», и «мир» как отдельные параметры echo.

Путем окружения строки метками двойной кавычки оболочка обрабатывает всю строку как отдельный аргумент к echo даже при том, что это содержит пробелы.

Чтобы видеть, как это работает, сохраните сценарий выше как test.sh (если Вы уже не имеете), затем введите следующие команды:

./test.sh leaders and citizens
./test.sh "leaders and citizens"

Первая строка выше печати “Привет, мировых лидеров!” потому что пространство после концов «лидеров» первый параметр ($1). В сценарии, переменной $1 содержит «лидеров», $2 содержит «и», и $3 содержит «граждан».

Вторая строка выше печати “Привет, мировых лидеров и граждан!” потому что кавычки на командной строке заставляют все в них быть сгруппированным как отдельный аргумент.

Заметьте также, что существуют подобные кавычки на правой стороне оператора присваивания:

FIRST_ARGUMENT="$1"

С большинством современных оболочек эти двойные кавычки не требуются для этого определенного оператора присваивания (потому что нет никаких литеральных пробелов на правой стороне), но они - хорошая идея для максимальной совместимости. Посмотрите, что Историческая Строка Анализирует в Исторических Сносках и Тайнах для изучения почему.

При присвоении литеральных строк (а не переменные, содержащие строки) к переменной, однако, необходимо окружить любые пробелы кавычками. Например, следующее утверждение не делает то, что Вы могли бы первоначально подозревать:

STRING2=This is a test

При вводе этого оператора Оболочка Bourne дает Вам ошибку как это:

sh: is: command not found

Причина этой на вид нечетной ошибки состоит в том, что концы оператора присваивания в первом пространстве, таким образом, следующее слово после того, как тот оператор интерпретируется как команда для выполнения. Посмотрите Переопределяющие Переменные окружения для Дочерних процессов (Оболочка Bourne) для большего количества подробных данных.

Вместо этого запишите этот оператор как:

STRING2="This is a test"

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

mkdir "/tmp/My Folder"
FILENAME="/tmp/My Folder"
ls "$FILENAME"
ls $FILENAME

Вышеупомянутый пример создает каталог в /tmp вызванный “Моя Папка”. (Не волнуйтесь об удалении его потому что /tmp вытерт каждый раз, когда Вы перезагружаете.) Это тогда пытается перечислить файлы в том каталоге. В первый раз это использует кавычки. Во второй раз это не делает. Заметьте, что оболочка неправильно истолковывает команду во второй раз, как являющийся попыткой перечислить файлы в /tmp/My и файлы в Folder.

Обработка кавычек в строках

В современных Оболочках Bourne, расширении переменных, происходит после того, как сам оператор полностью анализируется оболочкой. (См., что Историческая Строка Анализирует в Исторических Сносках и Тайнах для получения дополнительной информации.) Таким образом пока переменная включается в метки двойной кавычки, Вы не получаете ошибок выполнения, даже если значение переменной содержит метки двойной кавычки.

Однако при использовании меток двойной кавычки в литеральной строке необходимо заключить ту строку в кавычки должным образом. Например:

MYSTRING="The word of the day is \"sedentary\"."

Этот метод заключения в кавычки также применяется к литеральным строкам в командах, ввел в командную строку. Например, с помощью сценария от ранее в Переменных Shell и Печати, команде:

./test.sh "\"leaders\""

распечатывает фразу “Привет, мировых «лидеров»!”

Подробные данные кавычек, поскольку они применяются к переменному расширению, объяснены в Парсинге, Переменном Расширении и Заключении в кавычки. (Переменная безопасность с оболочками, предшествующими этому поведению, обычно непрактична. К счастью, современное поведение было нормой с середины 1990-х.)

Сценарии оболочки также позволяют использование меток одинарной кавычки. Переменные между одинарными кавычками не заменяются их содержанием. Обязательно используйте двойные кавычки, если Вы преднамеренно не пытаетесь вывести на экран подлинное имя переменной. Можно также использовать одинарные кавычки в качестве способа избежать оболочки, интерпретирующей содержание строки всегда. Эти различия описаны далее в Парсинге, Переменном Расширении и Заключении в кавычки.

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

Одна главная особенность сценариев оболочки - то, что переменные обычно ограничиваются в их объеме в настоящее время рабочим сценарием. Определение объема переменных описано более подробно в Подпрограммах, Определении объема и Определении источника. На данный момент, тем не менее, это достаточно, чтобы сказать, что переменные обычно не становятся переданными сценариям или инструментам, которые они выполняют.

Обычно, это - то, что Вы хотите. Большинство переменных в сценарии оболочки не имеет никакого подразумевать к инструментам, что они выполняются, и таким образом представляют помеху и потенциал для переменных конфликтов пространства имен, если они экспортируются. Иногда, однако, Вы сочтете необходимым сделать значение переменной доступным для внешнего инструмента. Чтобы сделать это, необходимо экспортировать переменную. Эти экспортируемые переменные обычно известны как переменные окружения, потому что они влияют на выполнение каждого сценария или инструмента, который работает, но не является частью тех сценариев или самих инструментов.

Классический пример переменной окружения, которая является значительной к сценариям и инструментам, PATH переменная. Эта переменная указывает список расположений, которые оболочка ищет при выполнении программ по имени (не указывая полный путь). Например, когда Вы вводите ls на командной строке оболочка ищет в расположениях, указанных в PATH (в указанном порядке), пока это не считает исполнимую программу вызванной ls (или исчерпывает расположения, какой бы ни на первом месте).

Подробные данные экспорта переменных оболочки отличаются значительно между Оболочкой Bourne и оболочкой C. Таким образом следующие разделы объясняют эти подробные данные специфичным для оболочки способом.

Используя экспорт, Встроенный (Оболочка Bourne)

Вообще говоря, в первый раз Вы присваиваете значение переменной окружения такой как PATH переменная, Оболочка Bourne создает новую, локальную копию этой переменной оболочки, которая является определенной для Вашего сценария. Любой инструмент, выполняемый из Вашего сценария, передается исходное значение PATH наследованный из любого сценария, инструмента или оболочки, запустившей его.

С оболочкой BASH, однако, любая переменная, наследованная от среды, автоматически экспортируется оболочкой. Таким образом, в некоторых версиях OS X, если Вы изменяете наследованные переменные окружения (такой как PATH) в сценарии Ваши локальные изменения будут замечены автоматически любым инструментом или сценарием, который выполняет Ваш сценарий. Таким образом, в этих версиях OS X, Вы не должны явно использовать export оператор при изменении PATH переменная.

Поскольку различные варианты Оболочки Bourne обрабатывают эти переменные внешней среды по-другому (даже среди различных версий OS X), это создает две незначительных проблемы мобильности:

  • Сценарий, записанный без export оператор может работать над некоторыми версиями OS X, но перестанет работать на других. Можно решить эту проблему мобильности при помощи export встроенный, как описано в этом разделе.

  • Сценарий оболочки, заменяющий переменные такой как PATH изменит поведение любого сценария, который оно выполняет, который может или может не быть желательным. Можно решить эту проблему путем переопределения PATH переменная окружения, когда Вы выполняете каждый отдельный инструмент, как описано в Переопределении Переменных окружения для Дочерних процессов (Оболочка Bourne).

Чтобы гарантировать, что Ваши модификации к переменной оболочки передаются любому сценарию или инструменту, который вызывает Ваш сценарий оболочки, необходимо использовать export встроенный. Вы не должны использовать эту команду каждый раз, когда Вы изменяете значение; переменная остается экспортируемой до выходов сценария оболочки.

Например:

export PATH="/usr/local/bin:$PATH"
# or
PATH="/usr/local/bin:$PATH"
export PATH

Любой из этих операторов имеет тот же эффект — в частности, они экспортируют локальное понятие PATH переменная окружения к любой команде, которую Ваш сценарий выполняет с этого времени. Существует маленькая выгода, как бы то ни было. Вы не можете позже отменить этот экспорт для восстановления исходного глобального объявления. Таким образом, если необходимо сохранить исходное значение, необходимо сохранить его где-нибудь сами.

В следующем примере сценарий хранит исходное значение PATH переменная окружения, экспортирует измененную версию, выполняет команду и восстанавливает старую версию.

ORIGPATH="$PATH"
PATH="/usr/local/bin:$PATH"
export PATH
# Execute some command here---perhaps a
# modified ls command....
ls
PATH="$ORIGPATH"

Если необходимо узнать ли переменная окружения (наследованный ли сценарием или явно набором с export директива), был установлен опустеть или никогда не устанавливался во-первых, можно использовать printenv команда для получения полного списка определенных переменных и использования grep видеть, находится ли это в списке. (Необходимо отметить это несмотря на то, что printenv csh встроенное, это - также автономная команда в /usr/bin.)

Например:

DEFINED=`printenv | grep -c '^VARIABLE='`

Получающаяся переменная будет содержать 1, если переменная будет определена в среде или 0, если это не.

Переопределение переменных окружения для дочерних процессов (оболочка Bourne)

Поскольку вариант Оболочки Bourne BASH автоматически экспортирует все переменные, наследованные от его среды, любые изменения, Вы делаете к существующим ранее переменным окружения такой как PATH автоматически наследованы любым инструментом или сценарием, который выполняет Ваш сценарий. (Это не истина для других вариантов Оболочки Bourne; посмотрите Используя экспорт, Встроенный (Оболочка Bourne) для дальнейшего объяснения.)

В то время как автоматический экспорт обычно удобен, можно иногда хотеть изменить существующую ранее переменную окружения, не изменяя среду никакого сценария или инструмента, который выполняет сценарий. Например, если Ваш сценарий выполняет много инструментов в /usr/local/bin, может быть удобно изменить значение PATH включать /usr/local/bin. Однако Вы не можете хотеть, чтобы также заглянули дочерние процессы /usr/local/bin.

Эта проблема легко решена путем переопределения переменной окружения PATH на основе на выполнение. Рассмотрите следующий сценарий:

#!/bin/sh
 
echo $MYVAR

Этот сценарий распечатывает значение переменной MYVAR. Обычно, эта переменная пуста, таким образом, этот сценарий просто распечатывает пустую строку. Сохраните сценарий как printmyvar.sh, тогда введите следующие команды:

chmod a+x printmyvar.sh      # makes the script executable
MYVAR=7 ./printmyvar.sh      # runs the script
echo "MYVAR IS $MYVAR"       # prints the variable

Заметьте что оператор присваивания MYVAR=7 применяется only к команде, следующей за ним. Значение MYVAR изменен в среде команды ./printmyvar.sh, таким образом, сценарий распечатывает номер 7. Однако исходное (пустое) значение восстанавливается после выполнения той команды, таким образом, оператор эха впоследствии распечатывает пустую строку для значения MYVAR.

Таким образом, для изменения PATH переменная локально, но выполняет команду с оригиналом PATH значение, можно записать сценарий как это:

#!/bin/sh
GLOBAL_PATH="$PATH"
PATH=/usr/local/bin
 
PATH="$GLOBAL_PATH" /bin/ls

Используя setenv Встроенное (оболочка C)

В оболочке C переменные экспортируются при установке их с setenv, но не, если Вы устанавливаете их с set. Таким образом, если Вы хотите, чтобы Ваши модификации переменной оболочки были замечены каким-либо инструментом или сценарием, который Вы вызываете, необходимо использовать setenv встроенный. Это встроенное является оболочкой C, эквивалентной выпуску оператора присваивания с export встроенный в Оболочке Bourne.

setenv VALUE "Four"
echo "VALUE is '$VALUE'."

Если Вы хотите, чтобы Ваши переменные оболочки только были доступны Вашему сценарию, необходимо использовать set встроенный (описанный в Переменных Shell и Распечатывающий). set встроенный эквивалентно простому оператору назначения в Оболочке Bourne.

set VALUE = "Four"
echo "VALUE is '$VALUE'."

Заметьте, что версия локальной переменной требует, равняется знаку (=), но экспортируемая версия среды не делает (и производит ошибку, если Вы вставляете один).

Для удаления переменных в оболочке C можно использовать unsetenv или unset встроенный. Например:

setenv VALUE "Four"
unsetenv VALUE
 
set VALUE = "Four"
unset VALUE
 
echo "VALUE is '$VALUE'."

Это генерирует сообщение об ошибке. В оболочке C не возможно распечатать значение неопределенной переменной, поэтому если Вы думаете, что Вы, возможно, должны распечатать значение позже, необходимо установить его в пустую строку вместо использования unset или unsetenv.

Если необходимо протестировать переменную окружения (не локальная переменная оболочки), который может или может не быть частью среды (переменная, установленная любым процессом, вызвала сценарий), можно использовать printenv встроенный. Это распечатывает значение переменной, если установлено, но ничего не распечатывает, если переменная не установлена, и таким образом ведет себя точно так же, как переменная ведет себя в Оболочке Bourne.

Например:

set X = `printenv VALUE`
echo "X is "\"$X\"

Это распечатывает X is "" если переменная или пуста или не определена. Иначе, это распечатывает значение переменной между кавычками.

Если необходимо узнать, пуста ли переменная просто или фактически не установлена, можно также использовать printenv получить полный список определенных переменных и использования grep видеть, находится ли это в списке. Например:

set DEFINED = `printenv | grep -c '^VARIABLE='`

Получающаяся переменная будет содержать 1, если переменная будет определена в среде или 0, если это не.

Переопределение переменных окружения для дочерних процессов (оболочка C)

В отличие от Оболочки Bourne, оболочка C не обеспечивает встроенный синтаксис для переопределения переменных окружения при выполнении внешних команд. Однако возможно моделировать это любой при помощи env команда.

Лучший и самый простой способ сделать это с env команда. Например:

env PATH="/usr/local/bin" /bin/ls

Как альтернатива, можно использовать set встроенный для создания временной копии любой переменной необходимо переопределить, изменить значение, выполнить команду и восстановить значение от временной копии.

Необходимо заметить, однако, это, используете ли Вы env команда или вручную делает копию, PATH переменная изменена до поиска команды. Поскольку PATH управление переменными, где оболочка ищет программы для выполнения, необходимо поэтому явно обеспечить полный путь к ls команда или это не будут найдены (если у Вас не будет копии в /usr/local/bin, конечно). PATH переменная окружения объяснена в Специальных Переменных Shell.

Как обходное решение, можно определить путь исполнимой программы с помощью which команда до изменения PATH переменная окружения.

set GLOBAL_PATH = "$PATH"
set LS = `which ls`
setenv PATH "/usr/local/bin"
$LS
setenv PATH "$GLOBAL_PATH"
unset GLOBAL_PATH

Или, использование env:

set LS = `which ls`
env PATH='/usr/local/bin' $LS

Использование обратной галочки (') оператор этим способом описано во Встроенном Выполнении.

Удаление переменных Shell

По большей части, в сценариях Оболочки Bourne, когда необходимо избавиться от переменной, установив его в пустую строку, достаточно. Однако в продолжительных сценариях, которые могли бы встретиться с давлением памяти, может быть незначительно полезно удалить переменную полностью. Чтобы сделать это, используйте unset встроенный.

Например:

MYVAR="this is a test"
unset MYVAR
echo "MYVAR IS \"$MYVAR\""

unset встроенный может также использоваться для удаления переменных окружения.