Bash Scripting Guide/Commands

Материал из Wiki.UnixForum.org

Перейти к: навигация, поиск

Содержание

Команды и комментарии

Любая строка скрипта является командой(несколькими командами), которая выполняется bash'ем. Также, в bash'е существуют комментарии -- куски кода, которые не выполняются ни при каких условиях. Комментарием считается всё, что стоит после символа #.

Например, строка:
# abc
Состоит только из комментария.

Примером команды может служить:

ls

Либо команда с аргументами:

echo hello

Двойные/одинарные кавычки и экранирование

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

Например,

echo hello > file

Запишет в файл file строку hello, а на экран ничего не выведет (см. Потоки ввода-вывода).

Тогда как:

echo 'hello > file'

Выведет

hello > file

В кавычки можно заключить даже перевод строки, он тоже потеряет при этом своё специальное назначение - завершение команды:

echo "first line
second line"

Выведет

first line
second line

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

echo \"

Для вывода обратной косой черты нужно её "удвоить":

echo \\

Оба этих способа вывода специальных символов почти равнозначны, так что выбор остаётся за вами (где-то быстрее поставить \, где-то кавычки).

Специальные символы

 ; # " ' ` \ $ ( ) [ ] { } > < & |
И некоторые другие в зависимости от контекста.

Подробнее можно прочитать по адресу: ABS Special Chars

Возвращаемые значения

Любая выполненная команда возвращает какое-то численное значение, по которому можно определить правильно выполнилась команда или нет. На основании этого возвращаемого значения можно и построить дальнейшую логику скрипта (например, выслать письмо администратору :-)).


Хозяйке на заметку: Принято, что:
  • 0 -- команда выполнилась без ошибок
  • всё остальное -- произошла какая-либо ошибка

Значение, возвращённое последней выполненной командой, находится в переменной $?.

Например,

ls /bad_folder/
echo $?

Выведет 1, так как /bad_folder/ не существует.

Выполнение нескольких команд

Первоначально, одна строчка -- одна команда. Для того, чтобы выполнить несколько команд в одной строке можно воспользоваться одним из трёх способов:

  • разделить команды точкой с запятой:

echo a; ls
Выполнит сначала команду echo, а потом ls

  • разделить команды двумя подряд идущими амперсандами:

echo a && ls
В таком случае вторая команда (ls) выполнится лишь в случае, когда первая команда (echo) вернёт 0, то есть выполнится без ошибок

  • разделить команды двумя подряд идущими вертикальными чертами:

echo a || ls
В этом же случае вторая команда выполнится только тогда, когда первая команда вернёт не 0, то есть выполнится с ошибкой

Команды можно группировать, объединяя их круглыми скобками.

Например,

ls /bad_file/ || ( echo a; echo b )

В таком случае содержимое круглых скобок, то есть:

echo a; echo b

Будет выполняться в отдельном подпроцессе bash'а. Что важно, например, при использовании exit -- будет завершён только подпроцесс, а основной процесс продолжит своё выполнение.

Чтобы подпроцесс не порождался, команды нужно объединять фигурными скобками.

Например, в случае

ls /bad_file/ || { echo a; echo b; }

echo a и echo b выполнятся только в том случае, если ls завершится с ошибкой. И они будут выполняться без порождения подпроцесса. Хочу обратить внимание, что точка с запятой после последней команды обязательна (в отличие от варианта с круглыми скобками, где точка с запятой возможна, но не обязательна).

Стоит отметить, что можно объединить несколько строк в одну (то есть bash будет считать их одной строкой) для этого в конце строке надо поставить один \:

echo a\
b

выведет ab (без пробелов!).

Потоки ввода/вывода

В любой программе существует три потока ввода/вывода:

  • stdin
    Используется для ввода данных в программу.
  • stdout
    Используется для вывода данных.
  • stderr
    Используется для вывода ошибок.

В bash'е каждый из этих потоков можно перенаправлять в файлы или друг в друга.

То есть

echo a > file

Перенаправит stdout в file, то есть a выведется не на экран, а перезапишет файл file.

Символ > является короткой записью для 1>, где 1 обозначает stdout. Для обозначения stderr нужно использовать 2.

Так, после

ls /bad_file/ 2>file

В файле file окажется строки ошибки:
ls: /bad_file/: No such file or directory

Так как > переписывает содержимое файла, то для дописывания в конец файла существует последовательность >> (перед ней так же возможны 1 и 2).

Например, после нескольких запусков:

ls /bad_file/ 2>file

В файле file так и останется одна строчка (содержимое файла будет при каждом вызове перезаписываться). Тогда как после нескольких выполнений

ls /bad_file/ 2>>file

В файле file будет содержаться несколько строчек (при каждом новом вызове будет дописываться ещё одна строка с ошибкой).

Ещё возможно перенаправить stdout в текущий stderr и наоборот. Для этого сразу после > или >> нужно дописать не имя файла, а амперсанд и номер потока:

ls /bad_file/ 2>&1

Перенаправит весь вывод stderr в stdout.

Также, можно сразу перенаправить оба потока в один и тот же файл:

ls /bad_file/ &>file

Правда, в такой форме записи невозможно дописывать в файл -- только перезаписывать.

Поток stdin перенаправляется символом <.

Например,

mysql < file

Будет считывать запросы из файла file, а не с экрана.

Хозяйке на заметку:
ls /bad_file/ 2>&1 >file

И

ls /bad_file/ >file 2>&1

Это разные перенаправления.

В первом случае stderr перенаправляется в stdout, а потом только stdout перенаправляется в файл file (stderr выводится на экран -- в момент перенаправления stdout указывал именно туда). Во втором случае сначала stdout перенаправляется в файл file, а затем туда же перенаправляется вывод stderr, то есть оба потока пишутся в файл file.

Конвейеры

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

Конвейер перенаправляет stdout одной программы в stdin другой (вместо вывода на экран).

Например,

echo "b
a" | sort

Здесь echo выводит в stdout

b
a

А затем этот вывод перенаправляет в stdin программы sort (потом вывод sort можно перенаправить куда-нибудь ещё, а потом ещё...).

Результатом будет:

a
b

Вообщем-то, благодаря конвейерам, у меня уже вошло в привычки писать:

cat file | grep "something"

Вместо

grep "something" file

В результате получится одно и то же, но если, например, я только что просматривал файл полностью (cat file), то первый вариант пишется быстрее. :-)

see also