"цепочка псевдонимов" в Bash или Zsh - PullRequest
0 голосов
/ 30 июня 2018

Это (или был , по крайней мере) общий шаблон в Ruby, но я не могу понять, как это сделать в Zsh или Bash.

Предположим, у меня есть функция оболочки, которая называется "whoosiwhatsit", и я хочу переопределить ее в конкретном проекте, сохраняя при этом доступность оригинала под другим именем.

Если бы я не знал лучше, я мог бы попытаться создать псевдоним, указывающий на whoosiwhatsit, а затем создать новую функцию "whoosiwhatsit", которая использует псевдоним. Конечно, это работает, поскольку псевдоним будет ссылаться на новую функцию.

Есть ли способ выполнить то, о чем я говорю?

Ответы [ 3 ]

0 голосов
/ 30 июня 2018

Распространено и хорошо поддерживается создание единого уровня переопределений с помощью функций, которые могут вызывать их переопределенные встроенные команды или команды:

# Make all cd commands auto-exit on failure
cd() { builtin cd "$@" || exit; }

# Make all ssh commands verbose
ssh() { command ssh -vv "$@"; }

Это не цепочка за одну ссылку, но это полностью POSIX и часто работает лучше, чем написание Ruby на Bash.

0 голосов
/ 30 июня 2018

Псевдонимы довольно слабые. Вы можете сделать это с помощью функций, хотя. Рассмотрим следующие инструменты:

#!/usr/bin/env bash

PS4=':${#FUNCNAME[@]}:${BASH_SOURCE}:$LINENO+'

rename_function() {
  local orig_definition new_definition new_name retval
  retval=$1; shift
  orig_definition=$(declare -f "$1") || return 1
  new_name="${1}_"
  while declare -f "$new_name" >/dev/null 2>&1; do
    new_name+="_"
  done
  new_definition=${orig_definition/"$1"/"$new_name"}
  eval "$new_definition" || return
  unset -f "$orig_definition"
  printf -v "$retval" %s "$new_name"
}

# usage: shadow_function target_name shadowing_func [...]
# ...replaces target_name with a function which will call:
# shadowing_func target_renamed_to_this number_of_args_in_[...] [...] "$@"
shadow_function() {
  local shadowed_func eval_code shadowed_name shadowing_func shadowed_func_renamed
  shadowed_name=$1; shift
  shadowing_func=$1; shift
  rename_function shadowed_func_renamed "$shadowed_name" || return
  if (( $# )); then printf -v const_args '%q ' "$@"; else const_args=''; fi
  printf -v eval_code '%q() { %q %q %s "$@"; }' \
    "$shadowed_name" "$shadowing_func" "$shadowed_func_renamed" "$# $const_args" 
  eval "$eval_code"
}

... и следующий пример применения этих инструментов:

whoosiwhatsit() { echo "This is the original implementation"; }

override_in_directory() {
  local shadowed_func=$1; shift
  local override_cmd_len=$1; shift
  local override_dir=$1; shift
  local -a override_cmd=( )
  local i
  for (( i=1; i<override_cmd_len; i++)); do : "$1"
    override_cmd+=( "$1" ); shift
  done
  : PWD="$PWD" override_dir="$override_dir" shadowed_func="$shadowed_func"
  : override_args "${override_args[@]}"
  if [[ $PWD = $override_dir || $PWD = $override_dir/* ]]; then
      [[ $- = *x* ]] && declare -f shadowed_func >&2 # if in debugging mode
      "${override_cmd[@]}"
  else
      "$shadowed_func" "$@"
  fi
}

ask_the_user_first() {
  local shadowed_func=$1; shift;
  shift # ignore static-argument-count parameter
  if [[ -t 0 ]]; then
    read -r -p "Press ctrl+c if you are unsure, or enter if you are"
  fi
  "$shadowed_func" "$@"
}

shadow_function whoosiwhatsit ask_the_user_first

shadow_function whoosiwhatsit \
  override_in_directory /tmp echo "Not in the /tmp!!!"

shadow_function whoosiwhatsit \
  override_in_directory /home echo "Don't try this at home"

Конечным результатом является функция whoosiwhatsit, которая запрашивает пользователя, прежде чем он что-либо предпримет, когда его стандартный ввод является TTY, и прерывается (с другими сообщениями) при запуске в режиме /tmp или /home.


Тем не менее, я не оправдываю эту практику. Рассмотрите вышеупомянутое как интеллектуальное упражнение. :)

0 голосов
/ 30 июня 2018

В bash есть встроенная переменная с именем BASH_ALIASES, которая представляет собой ассоциативный массив, содержащий текущие псевдонимы. Семантика немного противоречива, когда вы обновляете ее (RTM!), Но если вы ограничитесь чтением BASH_ALIASES, вы сможете написать себе функцию оболочки, которая реализует связывание псевдонимов.

...