从.bashrc或.zshrc修改现有函数

从.bashrc或.zshrc修改现有函数,bash,zsh,Bash,Zsh,/usr/share/zsh/functions/Completion/Unix/\u git (( $+functions[_git-diff] )) || _git-diff () { local curcontext=$curcontext state line ret=1 declare -A opt_args local -a diff_options diff_stage_options __git_setup_diff_options __git_setup_

/usr/share/zsh/functions/Completion/Unix/\u git

(( $+functions[_git-diff] )) ||
_git-diff () {
  local curcontext=$curcontext state line ret=1
  declare -A opt_args

  local -a diff_options diff_stage_options
  __git_setup_diff_options
  __git_setup_diff_stage_options

  _arguments -C -s $endopt \
    $* \
    $diff_options \
    '(--exit-code)--quiet[disable all output]' \
    $diff_stage_options \
    '(--cached --staged)--no-index[show diff between two paths on the filesystem]' \
    '(--cached --staged --no-index)'{--cached,--staged}'[show diff between index and named commit]' \
    '(-)--[start file arguments]' \
    '*:: :->from-to-file' && ret=0

  case $state in
    (from-to-file)
      # If "--" is part of $opt_args, this means it was specified before any
      # $words arguments. This means that no heads are specified in front, so
      # we need to complete *changed* files only.
      if [[ -n ${opt_args[(I)--]} ]]; then
        if [[ -n ${opt_args[(I)--cached|--staged]} ]]; then
          __git_changed-in-index_files && ret=0
        else
          __git_changed-in-working-tree_files && ret=0
        fi
        return ret
      fi

      # If "--no-index" was given, only file paths need to be completed.
      if [[ -n ${opt_args[(I)--no-index]} ]]; then
        _alternative 'files::_files' && ret=0
        return ret
      fi

      # Otherwise, more complex conditions need to be checked.
      case $CURRENT in
        (1)
          local files_alt='files::__git_changed-in-working-tree_files'
          if [[ -n ${opt_args[(I)--cached|--staged]} ]]; then
            files_alt='files::__git_changed-in-index_files'
          fi

          _alternative \
            'commit-ranges::__git_commit_ranges' \
            'blobs-and-trees-in-treeish::__git_blobs_and_trees_in_treeish' \
            $files_alt \
            'blobs::__git_blobs ' && ret=0
          ;;
        (2)
          # Check if first argument is something special. In case of committish ranges and committishs offer a full list compatible completions.
          if __git_is_committish_range $line[1]; then
            # Example: git diff branch1..branch2 <tab>
            __git_tree_files ${PREFIX:-.} $(__git_committish_range_last $line[1]) && ret=0
          elif __git_is_committish $line[1] || __git_is_treeish $line[1]; then
            # Example: git diff branch1 <tab>
            _alternative \
              'commits::__git_commits' \
              'blobs-and-trees-in-treeish::__git_blobs_and_trees_in_treeish' \
              'files::__git_tree_files ${PREFIX:-.} HEAD' && ret=0
          elif __git_is_blob $line[1]; then
            _alternative \
              'files::__git_cached_files' \
              'blobs::__git_blobs' && ret=0
          elif [[ -n ${opt_args[(I)--cached|--staged]} ]]; then
            # Example: git diff --cached file1 <tab>
            __git_changed-in-index_files && ret=0
          else
            # Example: git diff file1 <tab>
            __git_changed-in-working-tree_files && ret=0
          fi
          ;;
        (*)
          if __git_is_committish_range $line[1]; then
            # Example: git diff branch1..branch2 file1 <tab>
            __git_tree_files ${PREFIX:-.} $(__git_committish_range_last $line[1]) && ret=0
          elif { __git_is_committish $line[1] && __git_is_committish $line[2] } ||
              __git_is_treeish $line[2]; then
            # Example: git diff branch1 branch2 <tab>
            __git_tree_files ${PREFIX:-.} $line[2] && ret=0
          elif __git_is_committish $line[1] || __git_is_treeish $line[1]; then
            # Example: git diff branch file1 <tab>
            # Example: git diff branch -- f<tab>
            __git_tree_files ${PREFIX:-.} HEAD && ret=0
          elif __git_is_blob $line[1] && __git_is_blob $line[2]; then
            _nothing
          elif [[ -n ${opt_args[(I)--cached|--staged]} ]]; then
            # Example: git diff --cached file1 file2 <tab>
            __git_changed-in-index_files && ret=0
          else
            # Example: git diff file1 file2 <tab>
            __git_changed-in-working-tree_files && ret=0
          fi
          ;;
      esac
      ;;
  esac

  return ret
}
在上面

目前,我已经在我的
.zshrc
中复制粘贴了新函数,它正在工作

但是,我认为有一种更干净的方法可以使用
.bashrc
.zshrc
覆盖现有函数,如下所示:

_git-diff 2>/dev/null 
functions[_git-diff-orig]=$functions[_git-diff]  
_git-diff() {
    _git-diff-orig "$@"
    ... 
} 

但我不知道怎么做。谁能帮忙吗。为了清楚起见,我想使用
.bashrc
.zshrc
覆盖该函数,以便它更便于携带。

zsh
中,
函数
关联数组中的值是规范化的代码文本。这意味着您可以使用任何常用的文本操作方法对其进行修改:

foo(){
回音
回音
}
福
#=>之前
#=>之后
函数[foo]=${functions[foo]/echo before/echo before;echo during}
福
#=>之前
#=>在
#=>之后
函数foo
#=>foo(){
#=>之前的回声
#=>过程中的回声
#=>回声和后回声
# => }
有趣的是,zsh将解析、验证和规范化分配给
函数
数组时的代码——这与通常声明函数的过程基本相同。这就是为什么
函数foo
的输出有一个换行符,即使字符串替换使用了分号

将这些行添加到
~/.zshrc
应该适用于您的示例:

current=“'files::\uuu git\u tree\u files\${前缀:-.}HEAD'”
replacement=“'files::\u git\u changed\u files\${PREFIX:-.}HEAD'$current”
函数[\u git-diff]=${functions[\u git-diff]/$current/$replacement}
修改函数的其他方法 有许多方法可以改变shell语言中的文本,其中一些 对于更复杂的函数更改可能更有效。请注意,更多的更改 可能会使流程更加脆弱,因为对基本代码的更新可能会中断 加快修补过程

还请注意,更改将应用于存储在中的代码
函数
数组;这可能与原始源文件中的内容不匹配

使用
补丁
这是一个明显的选择,因为我们正在修补代码。
补丁
实用程序修改 基于
diff
(通常为
diff-u
)输出的文本。该实用程序可以处理 一些空白差异和一些错误,如行号不正确:

plan(){
预测=${1}
如果[[$forecast==sun]];则
打印“涂抹防晒霜”
打印“戴帽子”
elif[[$forecast==rain]];然后
打印“带伞”
打印“随身携带雨衣”
其他的
打印“待在家里”
fi
}
计划太阳
#=>涂防晒霜
#=>戴帽子
计划冰雹
#=>呆在家里
斑贴
---计划1
+++计划2
@@ -4,3 +4,5 @@
打印“涂抹防晒霜”
+打印“涂抹防晒霜”
打印“戴帽子”
+打印“使用太阳镜”
elif[[$forecast==rain]]
@@ -11,2 +13,3 @@
打印“待在家里”
+打印“放松”
fi'
函数[计划]=$(打印--$patchDiff\
|补丁-ls-o>(cat)=(打印--$functions[plan]))
计划太阳
#=>涂防晒霜
#=>涂抹防晒霜
#=>戴帽子
#=>戴太阳镜
计划冰雹
#=>呆在家里
#=>放松一下
使用
sed
使用
sed
流编辑器,在前面示例的基础上:

sedscript='s/print*\(.*\)/print${(C):-\1}/'
函数[plan]=$(打印$functions[plan]| sed-e$sedscript)
功能计划
#=>计划(){
#=>预测=${1}
#=>如果[[$forecast==sun]]
#=>那么
#=>打印${(C):-“涂防晒霜”}
#=>打印${(C):-“涂抹防晒霜”}
#=>打印${(C):-“戴帽子”}
#=>打印${(C):-“使用太阳镜”}
#=>elif[[$forecast==rain]]
#=>那么
#=>打印${(C):-“带伞”}
#=>打印${(C):-“携带雨衣”}
#=>其他
#=>打印${(C):-“呆在家里”}
#=>打印${(C):-“并放松”}
#=>fi
#=> }
计划下雨
#=>带伞
#=>携带雨衣
排队 这不需要匹配函数中的任何特定内容。两者都是 好的和坏的-它很容易实现,但即使是简单的 对基本函数的更改:

#将代码拆分为一个行数组(f)
行=(“${(f)函数[plan]}”)
在中间添加代码
新代码=(
${lines[1]}
'如果[[$forecast==tornado]];那么
打印“寻找避难所”
打印“快走”
返回
fi'
${行[2,-1]})
#用换行符重新连接数组(F)
函数[plan]=${(F)newCode}
功能计划
#=>计划(){
#=>预测=${1}
#=>如果[$forecast==龙卷风]]
#=>那么
#=>打印“寻找避难所”
#=>打印“快走”
#=>返回
#=>fi
#=>如果[[$forecast==sun]]
#=>那么
#=>打印${(C):-“涂防晒霜”}
#=>打印${(C):-“涂抹防晒霜”}
#=>打印${(C):-“戴帽子”}
#=>打印${(C):-“使用太阳镜”}
#=>elif[[$forecast==rain]]
#=>那么
#=>打印${(C):-“带伞”}
#=>打印${(C):-“携带雨衣”}
#=>其他
#=>打印${(C):-“呆在家里”}
#=>打印${(C):-“并放松”}
#=>fi
#=> }
计划龙卷风
#=>找到避难所
#=>快去

为了方便起见,您可以添加一个示例,其中
foo
有约10行文本。我想编辑第5行和第6行。我这样问是因为,我不知道如何在
functions[foo]=${functions[foo]/echo before/echo before;echo during}
'files::__git_tree_files ${PREFIX:-.} HEAD' && ret=0
_git-diff 2>/dev/null 
functions[_git-diff-orig]=$functions[_git-diff]  
_git-diff() {
    _git-diff-orig "$@"
    ... 
}