Используя extdebug на дисплей, где функция была определена


Я написал инструмент, похожий на which Что бы просмотреть файл и номер строки, где функция была определена. Есть ли способ я могу сделать то же самое для псевдонимов? Кроме того, какие-либо замечания или критику по коду?

function where() {
  cmd="$1"
  info=$(command -V "$cmd" | head -n 1)
  #rc="$PIPESTATUS[0]"

  case $info in
    *function*)
      shopt | grep -q extdebug
      extdebug=$?
      ! ((extdebug)) && shopt -s extdebug
      declare -F "$cmd"
      ! ((extdebug)) && shopt -u extdebug
      ;;
    *) echo "$info" ;;
  esac
}

Вывод выглядит:

$ where ls ; where l ; where bad ; where where
ls is /bin/ls
l is aliased to `ls -Al --color=auto'
bash: command: bad: not found

where 6 /home/harleypig/projects/dotfiles/.bash_sources.d/tools

Я понял, хотя он работал, я захватив выход из shopt|grep команды, не выйти из состояния.



95
1
задан 13 февраля 2018 в 05:02 Источник Поделиться
Комментарии
1 ответ

function where() Это не правильный синтаксис и работает только в некоторых версиях bash и zsh (и некоторые другие). Лучше писать либо function where или where().

shopt | grep -q extdebug ожидается, что всегда возвращает 0 для выхода кодекса, поскольку extdebug всегда в выходной shopt будет ли он включен или выключен, что это не ваше намерение, когда вы проверить ее статус. Вместо этого, вы должны написать shopt -q extdebug.

Глядя на ! ((extdebug)) && shopt -s extdebugЯ не знаю, если ! ((extdebug)) значение true или false. Получается, правда, когда extdebug равен 0 и false в противном случае. Это идет в счетчик, как состояние выхода из командной оболочки работы: 0 для успеха и ненулевой для отказа. Оба shopt -q extdebug и shopt | grep -q extdebug возвращает 0 (успех), если extdebug это, соответственно, набор и присутствуют в выходных shoptи 1 в противном случае. Так вы сидели extdebug когда он уже установлен, и отключение его, когда оно уже установлено. Лучше быть явным и писать ! shopt -q extdebug && shopt -s extdebug вместо.

Непонятно мне, почему info=$(command -V "$cmd") не хватает. Вы должны документировать случаи, когда это портит и трубопроводов head -n 1 нужен. Хотя, вероятно, немного меньше, портативный, info=$(type "$cmd") работает хорошо, тоже, и короче типа (Не каламбур), и выражает намерение лучше.

Вам не придется ограничивать, чтобы обрабатывать только первый аргумент, передаваемый этой функции, как command не обрабатывает только первый аргумент. Необходимые изменения тривиально. Я включаю весь модифицированную функцию ниже, с улучшенным форматированием:

function where
{
while (( $# > 0 ))
do
cmd=$1
info=$(type "$cmd")
case $info in
*function*)
#! shopt -q extdebug && shopt -s extdebug
shopt -s extdebug
declare -F "$cmd"
shopt -u extdebug
#shopt -q extdebug && shopt -u extdebug
;;
*)
echo "$info"
;;
esac
shift
done
}

Флажок проверять оболочка лишними, поэтому я прокомментировал это. Теперь выход будет выглядеть так:

$ where ls l bad where
ls is /bin/ls
l is aliased to `ls -Al --color=auto'
bash: type: bad: not found

where 6 /home/harleypig/projects/dotfiles/.bash_sources.d/tools

То же, вероятно, может быть сделано псевдоним, но это гораздо более увлекательный процесс. Вы, вероятно, нужно определить функцию с именем alias что вызывает строение alias в dotfile, которые получены во-первых, использовать callerсделать некоторые арифметические действия, чтобы получить правильный номер строки и сохраните результат в виде ассоциативного массива. Я буду размещать обновления, когда я мог заставить его работать.

Добавление

У меня есть доказательство концепции, чтобы сделать то же псевдоним, что ориентировочно строительство хотя и не всегда 100% точная:

declare -A alias_info

function alias
{
builtin alias "$@"
while (( $# > 0 ))
do
case $1 in
*=*)
IFS='=' read alias_name alias_command <<< "$1"
read line_no_in_sub caller_name source_file <<< "$(caller 0)"
if [[ -n "${source_file}" ]] # alias definition in sourced file
then
# line_no_in_sub is the line number relative to the function/script block,
# so we have to add to it the line number of the function.
shopt -s extdebug
func_line_no=$(awk '{print $2}' <<< "$(declare -F "${func_name}")")
shopt -u extdebug
alias_info[$alias_name]="$(( line_no_in_sub + func_line_no )) ${source_file} ${alias_name} is aliased to \`${alias_command}'"
else # alias definition from terminal
alias_info[$alias_name]="$(caller) $0 ${alias_name} is aliased to \`${alias_command}'"
fi
;;
*)
;;
esac
shift
done
}

2
ответ дан 13 февраля 2018 в 04:02 Источник Поделиться