Основы сценария оболочки
Запись сценария оболочки походит на поездку на велосипеде. Вы уменьшаетесь и очищаете колени много сначала. С немного большим опытом Вы становитесь удобной поездкой на них вокруг города, но также и быстро обнаруживаете, почему большинство людей управляет автомобилями для более длинных прохождений.
Сценарии Shell обычно считаются языком связующего звена, идеалом для создания маленьких частей кода, подключающих другие инструменты вместе. В то время как сценарии оболочки могут использоваться для более сложных задач, они обычно - не лучший выбор.
Если у Вас есть когда-нибудь успешно trued велосипедное колесо (или оплатил кому-то еще, чтобы сделать так), это подобно изучению основ сценариев оболочки. Если Вы не делаете истины Ваши сценарии, они колеблются. Другими словами часто просто записать сценарий, но это может быть более сложно для записи сценария, последовательно работающего хорошо.
Эта глава и следующие две главы представляют фундаментальные понятия сценариев оболочки. Остающиеся главы в этом документе обеспечивают дополнительную ширину и глубину. Этот документ не предназначается, чтобы быть полной ссылкой при записи сценариев оболочки, и при этом это не могло быть. Это действительно, однако, предоставляет хорошую начальную точку новичкам, сначала изучающим эту черную магию.
Диалекты сценария оболочки
Существует много различных диалектов сценариев оболочки, каждого с их собственными причудами и некоторых с их собственным синтаксисом полностью. Из-за этих различий дорога к хорошим сценариям оболочки может быть чревата опасностью, приведя к отказам сценария, неправомерному поведению и даже прямой потере данных.
С этой целью первый урок, который необходимо извлечь прежде, чем записать сценарий оболочки, - то, что существует два существенно различных набора синтаксиса сценария оболочки: синтаксис Оболочки Bourne и синтаксис оболочки C. Синтаксис оболочки C более удобен для многих программистов C, потому что синтаксис несколько подобен. Однако синтаксис Оболочки Bourne значительно более гибок и таким образом более широко используется. Поэтому этот документ только касается синтаксиса Оболочки Bourne.
Второй тяжелый урок, который Вы неизменно извлечете, - то, что каждый диалект синтаксиса Оболочки Bourne отличается немного. Этот документ включает только чистый синтаксис Оболочки Bourne и несколько СПЕЦИФИЧНЫХ ДЛЯ BASH расширений. Где СПЕЦИФИЧНЫЙ ДЛЯ BASH синтаксис используется, он ясно отмечен.
Терминология и тонкие синтаксические различия могут сбить с толку — даже немного подавляющий время от времени; имел Дороти в Мастере Оза, программист, Вы, возможно, услышали, что она воскликнула, «BASH и ZSH и CSH, О Мой!» К счастью, как только Вы получаете основы, вещи обычно встают на свое место, пока Вы избегаете использования специфичных для оболочки функций. Останьтесь на узкой дороге, и Ваш код будет переносимым.
Некоторые общие оболочки упоминаются ниже, группируются синтаксисом сценария:
Совместимые с границей оболочки
Совместимые с оболочкой C оболочки
Многие из этих оболочек имеют больше чем одно изменение. Большинство этих изменений обозначено путем добавления префикса имени существующей оболочки с дополнительными буквами, которые коротки для того, что дифференцирует их от исходной оболочки. Например:
Оболочка
pdksh
вариантksh
. Быть перезаписью общественного достояния AT&Tksh
, это выдерживает за «Общественное достояние Оболочку Korn». (Это - что-то вроде неправильного употребления, поскольку несколько битов действуют в соответствии с подобной BSD лицензией Open Source. Однако имя остается.)Оболочка
tcsh
расширениеcsh
. Это обозначает Оболочку C TENEX, поскольку некоторые ее улучшения были вдохновлены операционной системой TENEX.Оболочка
bash
расширениеsh
. Это выдерживает за Границу Снова Оболочку. (Достаточно странно это не изменениеash
, Оболочка Almquist, хотя оба - варианты Оболочки Bourne. Это не должно быть перепутано сdash
оболочка —ash
- полученная оболочка использовала в некоторых дистрибутивах Linux — чье имя обозначает Оболочку Debian Almquist.)
И т.д. В целом, за исключением 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
встроенный может также использоваться для удаления переменных окружения.