Воссоздание блока 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 утверждение из необычных аргументов), и делает работу в одну строку.

Очень возможно, я отвечаю на не заданный вопрос. Извинения если так; не в первый раз:-)

Другие вопросы по тегам