9 занимательных вещей о shell, о которых вы могли не знать
Очень сложно представить работу админа без использования терминала и командной оболочки. Сегодня мы поговорим о shell и тонкостях работы с ним.
Давайте же узнаем, какие занимательные вещи хранит в себе Bourne again shell.
Bash – это не только командный процессор, а еще и полноценный язык программирования, используемый для автоматизации рутинных процессов и кодинга. В сети можно найти массу материалов с информацией разного уровня сложности. В этой статье мы собрали 9 фактов, которые могут облегчить вашу жизнь и сделать простое еще проще.
1) ''
vs $()
Эти два оператора выполняют одно и то же. Сравните 2 строки:
$ echo `ls` $ echo $(ls)
Если вы не знаете, обе формы заменяют вывод команды, содержащейся в них командой. Главное отличие в том, что вложение проще.
Какая из этих строк проще читается (и пишется)?
$ echo `echo \`echo \\\`echo inside\\\`\``
или:
$ echo $(echo $(echo $(echo inside)))
2) Подстановка vs regexps
Очень коварная штука, которая не всегда понятна с первого раза. Хотя подстановка и регулярное выражение может выглядеть одинаково, они будут выполнять разные действия. Посмотрим на строку:
$ rename -n 's/(.*)/new$1/' *
Две звездочки интерпретируются по-разному.
Первая звездочка игнорируется оболочкой (потому что она в кавычках) и интерпретируется как «0 или более символов». Таким образом, это распознаётся как регулярное выражение.
Вторая – трактуется shell-ом (потому что она не входит в кавычки), и заменяется списком всех файлов в текущей рабочей папке. Интерпретируется как подстановка.
Если обратиться к man bash
, вы сможете понять, почему эти две команды выдают разные результаты?
$ ls * $ ls .*
Второе выражение больше похоже на регулярное выражение, но это не так.
3) Коды выхода
Не все знают, что каждый раз, когда вы запускаете команду в shell, в оболочку возвращается «код выхода».
Как правило, если команда успешно выполняется, вы получаете код 0, иначе – ненулевое значение. Единица является «общей ошибкой», а другие могут дать вам дополнительную информацию (например, какой сигнал убил ее).
Но эти правила не всегда выполняются:
$ grep not_there /dev/null $ echo $?
$?
– специальная переменная bash, которой назначается код завершения каждой команды после ее запуска. Grep использует код выхода, чтобы показать, нашлось что-то или нет.
4) Условные операторы, [ и [[
Вот еще один кусок кода, который похож на предыдущий пример:
if grep not_there /dev/null then echo hi else echo lo fi
Вместо кода выхода grep возвращает значение из кода.
Что выведет код:
- hihi
- lolo
- something else
if [ $(grep not_there /dev/null) = '' ] then echo -n hi else echo -n lo fi if [[ $(grep not_there /dev/null) = '' ]] then echo -n hi else echo -n lo fi
В первом блоке if
не имеет смысла потому, что $(grep not_there /dev/null)
– это пустота, которая приводит к такому сравнению:
[ = '' ]
Иногда можно встретить странное сравнение:
if [ x$(grep not_there /dev/null) = 'x' ]
оно ничего не возвращает, но продолжает работать.
5) set s
У Bash есть настраиваемые параметры, которые можно установить «на лету». Довольно часто используются два из них:
set -e
выход из сценария, если какая-либо команда вернула ненулевой код.
Это выводит команды, которые запускаются при запуске скрипта:
set -x
Таким образом, сценарий может начинаться так:
#!/bin/bash set -e set -x grep not_there /dev/null echo $?
Что выведет код?
6) < ( )
Данный приём мало где используется, возможно, потому, что это может сильно озадачить пользователя.
Схожесть с $()
заключается в том, что вывод команды внутри повторно используется. В этом случае вывод обрабатывается как файл и может быть использован в команде, которая принимает такие аргументы.
Вы делали когда-нибудь подобное?
$ grep somestring file1 > /tmp/a $ grep somestring file2 > /tmp/b $ diff /tmp/a /tmp/b
Это сработает, но можно было написать так:
diff <(grep somestring file1) <(grep somestring file2)
7) Кавычки
Кавычки – ключевой объект в bash, как и во многих контекстах программного обеспечения.
Во-первых, переменные в кавычках:
A='123' echo "$A" echo '$A'
Довольно просто – двойные кавычки разыменовывают переменные, а одинарные кавычки приводят к литералу.
Какой вывод будет здесь?
mkdir -p tmp cd tmp touch a echo "*" echo '*'
8) Полезные указатели
В man bash
есть масса примеров указателей, которые значительно облегчают жизнь. Здесь мы рассмотрим три распространенных указателя, а наиболее очевидные (например, !!
– повторить последнюю команду и ~
– домашний каталог) опустим.
!$
– повторяет последний аргумент последней команды. Если вы работаете с файлом, то можете не тратить время на ввод дублирующей строки:
grep somestring /long/path/to/some/file/or/other.txt vi !$
!:1-$
– берет все аргументы предыдущей команды и запоминает.
grep isthere /long/path/to/some/file/or/other.txt egrep !:1-$ fgrep !:1-$
!
означает «смотреть на предыдущую команду», :
– разделитель, 1
означает «взять первое слово», –
означает «до», $
– последнее слово.
Похожего результата можно добиться при помощи !*
. Этот указатель дает возможность ограничить определенное непрерывное подмножество аргументов, например, с помощью !:2-3
.
:h
– если поместить данную команду после имени файла, он изменит имя файла, чтобы удалить все до папки.
grep isthere /long/path/to/some/file/or/other.txt cd !$:h
9) Порядок загрузки
Запоминание порядка, в котором shell
запускает сценарии, может вызвать бурю эмоций. Вот вам диаграмма того, что происходит у shell
«в голове»:
Она показывает, как shell
решает запускать скрипт в зависимости от контекста, в котором он запущен (цветами указаны принимаемые решения).
Поэтому если вы находитесь в локальной (не ssh
), nologin
, интерактивной оболочке (например, когда запускаете shell
из командной строки), это зеленая линия:
/etc/bash.bashrc ~/.bashrc [bash runs, then terminates] ~/.bash_logout
Bash
– очень занятная оболочка, которая имеет большой потенциал и приносит огромную пользу в ежедневной рутине. Рассмотренные примеры команд облегчат работу в командной строке *nix
системы. Не останавливайтесь на этих трюках, исследуйте дальше бескрайние просторы bash
и будьте аккуратны с rm -rf /
.