Shell: передать функцию с аргументами в качестве аргумента функции - PullRequest
1 голос
/ 11 июля 2019

Я работаю над программой оболочки для автоматизации моей установки Arch (обязательно btw ).Чтобы сделать его более интерактивным, я построил следующую функцию:

  # READYN
  #   ARGS:
  #   - Yes/no question
  #   - Command to run if yes
  #   - Command to run if no
  #
  #   Prompts the user with a yes/no question (with precedence for yes) and
  #   run an order if the answer is yes or another if it's no.

readyn () {
  while :
  do
    local yn;

    printf "%s? [Y/n]: " "$1";
    read yn;

    if [[ "$yn" =~ ^([yY][eE][sS]|[yY])?$ ]]; then
      $2;
      break;
    elif [[ "$yn" =~ ^([nN][oO]|[nN])+$ ]]; then
      $3;
      break;
    fi
  done
}

Мне удалось передать "echo Hello World!" в качестве аргумента и запустить его.Я также смог передать другую функцию.Например:

yayprompt () {
  printf "yay is required to install %s.\n" "$1"
  readyn "Install yay, the AUR manager" "yayinstall" ""
}

Это вызывает yayinstall, если да, и ничего не делает, если нет.

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

  # MANAGEPGK
  #   ARGS:
  #   - Package name
  #   - Package variable
  #   - Yay required
  #
  #   Checks if the package is added to the pkglist to either add or remove it.
  #   If yay is required to install it, it prompts the user whether they wish
  #   to install yay or don't install the package (if yay is not installed).
  #   This functions DOES NOT prompt any installation options on the user. To
  #   do this, use PROMPTPKG.

managepkg () {
  local pkgvar=$2

  if [ $pkgvar == 0 ]; then
    if [ $3 == 1 ] && [ $yay == 0 ]; then
      yayprompt;
    fi

    if [ $3 == 0 ] || [ $yay == 1 ]; then
      addpkg "$1";
      pkgvar=1;
    fi
  else
    rmpkg "$1";
    pkgvar=0;
  fi

  echo "$pkgvar";
}

Чтобы она работала правильно, она должна (или, по крайней мере, должна была) вызываться так:

dewm_cinnamon=$(managepkg cinnamon $dewm_cinnamon 0)

Теперь я пытаюсь передать его в качестве аргумента readyn, но у меня есть эти выходные данные в зависимости от формата (я всегда отвечаю yes пустой строкой:

Простые кавычки:

readyn "Install gaps" \
       'dewm_i3gaps=$(managepkg i3-gaps $dewm_i3gaps 0)' \
       'dewm_i3=$(managepkg i3-wm $dewm_i3 0)';
Install gaps? [Y/n]:
./architup.sh: line 341: dewm_i3gaps=$(managepkg: command not found

Двойные кавычки:

readyn "Install gaps" \
       "dewm_i3gaps=$(managepkg i3-gaps $dewm_i3gaps 0)" \
       "dewm_i3=$(managepkg i3-wm $dewm_i3 0)";
Install gaps? [Y/n]: 
./architup.sh: line 341: dewm_i3gaps=1: command not found

Доллар прилагается: (Этокаждый запускает обе команды, как показано в cat pkglist)

readyn "Install gaps" \
       $(dewm_i3gaps=$(managepkg i3-gaps $dewm_i3gaps 0)) \
       $(dewm_i3=$(managepkg i3-wm $dewm_i3 0));
Install gaps? [Y/n]: 
Install compton? [Y/n]: ^C

Documents/Repositories/architup took 5s 
➜ cat pkglist
i3-gaps
i3-wm

Какой синтаксис я должен использовать, чтобы readyn run only одна команда, основанная на пользовательском вводе?

Спасибо!

1 Ответ

1 голос
/ 11 июля 2019

Аргументы функции - это просто строки.Лучшее решение IMHO - просто readyn возвращать true (ноль) для «yes» и false в противном случае, а вызывающий код должен реализовывать любую условную логику, основанную на этом.

readyn () {
    read -p "$@"
    case $REPLY in
        [Yy] | [Yy][Ee][Ss]) return 0;;
    esac
    return 1
} 

readyn "Are you ready San Antonio?" &&
rock and roll

if readyn "Let me hear you say yeah"; then
    echo "Let's go!"
else
     echo "If you feel mellow, get outta here"
fi

(с извинениями зарок-концерты везде,)

...