В командной строке или в сценариях оболочки есть три основных способа взаимодействия команд друг с другом. Первый и второй способ – через файловый ввод-вывод через каналы и среду. Третий способ – через параметр команды. Однако, чтобы команда могла взаимодействовать с другой через параметры, она или ее результат должны быть включены в список параметров. Вот где в игру вступает расширение команд или подстановка команд. Здесь мы рассмотрим все, что вам нужно знать о подстановке команд, чтобы писать сценарии bash, как босс!
Подстановка команд – это основная функция оболочки, которая позволяет выводить одну или несколько команд на месте и использовать их, как расширение переменных, в качестве аргументов для расширения другой команды. Другими словами, результат выполнения команд помещается в недолговечную анонимную переменную и подставляется в окружающую команду.
Есть два приемлемых синтаксиса или способов выполнения подстановки команд в bash:
На данный момент оба пути представлены без нашего мнения.
В дикой природе, когда разработчиков заставляют писать сценарии bash, по нашему опыту, тот или иной синтаксис используется в зависимости от личных предпочтений.
$( command )
На наш взгляд, этот синтаксис легче читать, особенно при вложенных подстановках команд, не говоря уже о том, что он менее подвержен ошибкам.
Большинство сред Linux с такими командами Coreutils, как cat и shuf, также оснащены командой wc, которая позволяет вам подсчитывать байты, слова и строки в файле. Здесь мы будем использовать его, чтобы просто проверить, содержит ли файл больше определенного количества строк, а затем что-нибудь предпринять.
test ! $( seq 101 | wc -l ) -gt 100 || { echo do something }
Примечание
Выражение $( seq 101 | wc -l ) оценивается как целое число 101. В результате выражение test принимает вид test! 101 -gt 100. Кроме того, мы можем вывезти! оператор конвейера и вычисление оставшегося тестового выражения. То есть. Надеюсь, вы согласитесь, что test 101 -gt 100 действительно верен. Затем мы остались с! true в левой части оператора списка ||. ! истина становится ложью; и ложь || становится истинным &&.
`command`
Если вам нравятся обратные кавычки больше, чем деньги, отлично! Как и в природе кодирования, вы можете писать код любым удобным для вас способом, если только вы не должны соблюдать некоторые строгие правила стиля. Мы просто скажем, что у вас могут возникнуть трудности с подстановкой вложенных команд.
Давайте упростим и выведем сообщение с вашим именем пользователя.
echo my username is `whoami`
Примечание
Если ваше имя пользователя «andreyex», приведенная выше команда оценивается как «my username is andreyex».
Теперь, когда вы знаете, как использовать подстановку команд, давайте рассмотрим способы ее использования.
Часто мы хотим присвоить переменной результат выполнения команды. Это можно сделать с помощью подстановки команд.
variable=$( command args... )
Например, при сопоставлении с шаблоном bash мы присвоили переменной подчиненные буквы алфавита следующим образом.
Команды
subject=$( echo {z..a} | tr -d ' ' ) echo ${subject}
Вывод
zyxwvutsrqponmlkjihgfedcba
Удобный! Разве вы не рады, что сейчас произошла подмена команды!
Давайте свернем нашу собственную функцию карты, которая подсчитывает количество слов, содержащих букву a.
Во-первых, нам нужна функция, которая проверяет, содержит ли какое-то слово букву a. В следующем фрагменте мы будем использовать замену шаблона с помощью расширения параметра и целочисленного атрибута в назначении.
Команды
has_a() { local instr="${1}" local -i match=$( test ! "${instr//a}" != "${instr}" || echo 1 ) echo ${match} }
Если результат замены a из входной строки не является самим собой до замены, мы говорим, что входная строка содержит букву a. В этом случае мы повторяем 1. Результирующая подстановка команды затем подлежит присвоению с целочисленным атрибутом. В случае присвоения пустого значения присвоенное значение принимается равным 0. То есть функция has_a возвращает 0 или 1 в зависимости от наличия буквы a во входной строке.
Вот краткий обзор нашей функции has_a в действии.
Команды
has_a asdf has_a sdf has_a df has_a f has_a a
Вывод
1 0 0 0 1
Затем нам нужна функция для циклического перебора слов в предложении с применением функции has_a, которую мы просто назовем map.
Команды
map() { test ! ${#} -eq 1 || { true ; return ; } local function_name="${1}" local first=${2} local rest=${@:3} echo "$( ${function_name} ${first} ) $( map ${function_name} ${rest} )" }
Вот краткий обзор нашей функции карты в действии.
Команды
map has_a a b c map has_a {a..z}{a..z} map has_a {a..b}{a..b}{a..b}
Вывод
1 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 00 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 00 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0
Теперь вы в матрице!
Все, что нам нужно сделать сейчас, это подсчитать единицы, которые мы назовем суммой.
sum() { test ! ${#} -eq 1 || { echo 0 ; return ; } local -i first="${1}" local rest=$( sum ${@:2} ) first+=rest echo ${first} }
Это должно сработать!
Вот краткий обзор нашей функции суммы в действии.
Команды
sum $( map has_a {a..b}{a..b}{a..b} ) sum $( map has_a {a..z}{a..z} ) sum $( map has_a {a..c}{a..c} )
Вывод
7 51 5
Пока вы здесь, давайте еще немного повеселимся с присваиваниями, исследуя то, что я люблю называть функциями настройки, т.е. мы собираемся создать специализированную функцию для присвоения значения переменной. Как вы уже знаете, нам может потребоваться подстановка команд. Вот как:
Команды
variable() { echo 1 } setup-variable() { variable=$( variable ) } setup() { setup-variable } main() { local variable=0 setup echo ${variable} } main echo ${variable:-empty}
Вывод
1 empty
Круто! Теперь вы можете использовать расширение команды bash! Как и следовало ожидать, возможность расширять код в команды по своему усмотрению дает вам преимущество при попытке решить реальные проблемы с помощью программирования на bash в дополнение к созданию повторно используемого кода. Кодируйте ответственно.