Воссоздание блока if/then из сценария оболочки в C для использования в сценариях оболочки
Интересно, можно ли каким-либо образом создать функцию / набор функций в C, которые компилируются в сценарий оболочки для условной оценки. Например, возьмем условный блок, например:
if [[ "${USER}" == "root" ]]; then
userStyle="${red}";
else
userStyle="${orange}";
fi;
Это обычный сценарий оболочки. Мне интересно, есть ли какой-нибудь способ создать функции C, чтобы вы могли альтернативно написать так в сценарии оболочки:
ifblock "${USER}" == "root" {
userStyle="${red}";
}
elseblock {
userStyle="${orange}";
}
(Я просто используюxblock
для предотвращения именных коллизий)
Если не так, некоторые альтернативные формы могут быть:
ifblock \
("${USER}" == "root") \
(userStyle="${red}";) \
(userStyle="${orange}";)
Или, если требуется обернуть все в локальные функции (если это так), это тоже будет работать:
test_user() {
"${USER}" == "root"
}
test_user_true() {
userStyle="${red}";
}
test_user_false() {
userStyle="${orange}";
}
ifelse test_user test_user_true test_user_false
В идеале что-то вроде первого способа имеет больше смысла, но в основном мне просто интересно, есть ли способ имитировать поток управления в сценарии оболочки, не прибегая к примитивам потока управления.
Я не уверен, как будет выглядеть функция C для реализации этого.
2 ответа
Вы действительно можете написать внешние команды, которые условно вызывают команды, указанные в качестве параметров. Типичный пример find
:
find . -type f -exec grep -q 'mystring' {} \; -exec echo "I found a matching file" \;
это в основном эквивалентно
for file in **/*
do
if grep -q 'mystring' "$file"
then
echo "I found a matching file"
fi
done
Однако, поскольку внешние команды требуют разветвления нового процесса, такая программа не сможет использовать или влиять на среду текущего процесса. Например, он не может:
- Изменить переменные в вызывающем скрипте
- Чтение неэкспортированных переменных в вызывающем скрипте
- Изменить текущий каталог вызывающего скрипта
- Вызовите функции, которые требуют какого-либо из вышеперечисленных
Вы можете продвинуться немного дальше, написав функции Bash вместо внешних исполняемых файлов, но если вы хотите создать гибкий EDSL, то Bash действительно не тот язык.
Похоже, что в этой истории чего-то не хватает: почему реализация чего-то условного в сценарии оболочки без "обращения к" обычным встроенным управляющим операторам имеет значение... какое-либо просвещение, OP? (Кстати, я согласен с выводами that other guy - хороший список предостережений, а DSL-подобные вещи на основе bash или других оболочек неудобны.)
Тем не менее, проверьте мое понимание: смысл вашего примера в том, чтобы иметь простую команду вроде:
ifelse test_user test_user_true test_user_false
... привести к установке переменной оболочки userStyle
условно? Так что userStyle установлен в значение red
в одном случае (пользователь "root"), значение orange
в другом?
Если это так, оставляя текущую оболочку вызывать отдельный исполняемый файл с именем ifelse
чувствует себя переваренным Эта вызванная программа видит только аргументы командной строки - простые строки, такие как "test_user", "test_user_true", "test_user_false". Предположительно, вы хотите вызвать ifelse
исполняемый файл, чтобы знать вышеуказанную логику red
а также orange
Но наличие вызываемого исполняемого файла влияет на вызывающую оболочку неудобно и подвержено проблемам с безопасностью. возможно ifelse
испускает команды оболочки самостоятельно, что вызывающая оболочка должна (доверять и затем) source
или же eval
, Кажется довольно рискованным и неудобным в обслуживании, и получающееся в результате использование оказывается не таким простым в вызывающей оболочке, как вы хотите:
eval $(ifelse test_user test_user_true test_user_false)
Пребывание в текущей оболочке может работать - возможно, это близко к тому, что вы ищете. Рассмотрите следующую переписывание кода выше (обратите внимание на изменениеtest_user
):
red='This is the RED user style'
orange='This is the ORANGE user style'
test_user() {
[ "${USER}" = "root" ]
}
test_user_true() {
userStyle="${red}"
}
test_user_false() {
userStyle="${orange}"
}
ifelse() {
if "$1"; then
"$2"
else
"$3"
fi
}
ifelse test_user test_user_true test_user_false
echo "User Style: $userStyle"
Так как я не root, если я запускаю это, я вижу:
User Style: This is the ORANGE user style
Возвращаясь к моей первой редакционной статье, если мы застряли в оболочке, мне все еще неясно, как ifelse
Функция оболочки много покупает. Вместо этого рассмотрим:
if test_user; then test_user_true; else test_user_false; fi
Нет необходимости в этом фанки ifelse
функция (и его веселая готовность построить инвалид if
утверждение из необычных аргументов), и делает работу в одну строку.
Очень возможно, я отвечаю на не заданный вопрос. Извинения если так; не в первый раз:-)