【问题标题】:git diff with line numbers and proper code alignment/indentation带有行号和正确代码对齐/缩进的 git diff
【发布时间】:2020-09-07 23:03:06
【问题描述】:

我得到了这个代码示例from someone else here:

  git diff --color=always | \
    gawk '{bare=$0;gsub("\033[[][0-9]*m","",bare)};\
      match(bare,"^@@ -([0-9]+),[0-9]+ [+]([0-9]+),[0-9]+ @@",a){left=a[1];right=a[2];next};\
      bare ~ /^(---|\+\+\+|[^-+ ])/{print;next};\
      {line=gensub("^(\033[[][0-9]*m)?(.)","\\2\\1",1,$0)};\
      bare~/^-/{print "-"left++ ":" line;next};\
      bare~/^[+]/{print "+"right++ ":" line;next};\
      {print "("left++","right++"):"line;next}'

并希望它输出正确对齐的行。不幸的是,它可能会像这样在您的git diff 中输出行号:

+240:+ some code here
(241,257): some code here

而不是这样强制对齐:

+240     :+some code here
(241,257): some code here

这是我尝试过的一件事,认为 printf 可能会成功(例如:printf "-%-8s:"):

  git diff HEAD~..HEAD --color=always | \
    gawk '{bare=$0;gsub("\033[[][0-9]*m","",bare)};\
      match(bare,"^@@ -([0-9]+),[0-9]+ [+]([0-9]+),[0-9]+ @@",a){left=a[1];right=a[2];next};\
      bare ~ /^(---|\+\+\+|[^-+ ])/{print;next};\
      {line=gensub("^(\033[[][0-9]*m)?(.)","\\2\\1",1,$0)};\
      bare~/^-/{printf "-%-8s:" left++ line;next};\
      bare~/^[+]/{printf "+%-8s:" right++ line;next};\
      {print "("left++","right++"): "line;next}'

但它会产生这个错误:

gawk: cmd. line:5: (FILENAME=- FNR=9) fatal: not enough arguments to satisfy format string
    `-%-8s:151-    STR_GIT_LOG="" #######'
        ^ ran out for this one

这个 bash 脚本目前只是在我的脑海中,我一直在修补它很长一段时间。也许有人可以帮助我?

此外,数字和 +/- 符号应分别为绿色和红色,就像在正常的 git diff 输出中一样。


由 Ed Morton 编辑 - 通过使用带有 gawk 5.0.1 的 gawk -o- 漂亮地打印 OPs 代码使其可读:

$ gawk -o- '{bare=$0;gsub("\033[[][0-9]*m","",bare)};\
  match(bare,"^@@ -([0-9]+),[0-9]+ [+]([0-9]+),[0-9]+ @@",a){left=a[1];right=a[2];next};\
  bare ~ /^(---|\+\+\+|[^-+ ])/{print;next};\
  {line=gensub("^(\033[[][0-9]*m)?(.)","\\2\\1",1,$0)};\
  bare~/^-/{print "-"left++ ":" line;next};\
  bare~/^[+]/{print "+"right++ ":" line;next};\
  {print "("left++","right++"):"line;next}'

.

{
    bare = $0
    gsub("\033[[][0-9]*m", "", bare)
}

match(bare, "^@@ -([0-9]+),[0-9]+ [+]([0-9]+),[0-9]+ @@", a) {
    left = a[1]
    right = a[2]
    next
}

bare ~ /^(---|\+\+\+|[^-+ ])/ {
    print
    next
}

{
    line = gensub("^(\033[[][0-9]*m)?(.)", "\\2\\1", 1, $0)
}

bare ~ /^-/ {
    print "-" left++ ":" line
    next
}

bare ~ /^[+]/ {
    print "+" right++ ":" line
    next
}

{
    print "(" left++ "," right++ "):" line
    next
}

【问题讨论】:

  • 一些空格和缩进会LONG 让您的代码更具可读性。
  • 现在打印很漂亮,我可以看到您在正则表达式周围使用字符串分隔符 ("...") 而不是正则表达式分隔符 (/.../) - 不要这样做,因为这会强制 awk在将字符串用作正则表达式之前先解释字符串,因此您需要将所有内容转义两次以解释双重解析。因此,例如,"^(\033[[][0-9])" 需要为 /^(\033[[][0-9])/"^(\\033[[][0-9])",后者是不可取的。
  • edit 您的问题提供简洁、可测试的示例输入和预期输出(不是链接,不是图像,只是文本),因此我们可以帮助您做任何您想做的事情。顺便说一句,你的问题的唯一部分是两个命令之间的管道符号|,这不是特定于 bash 的。当您说This bash script is just way over my head 时,您寻求帮助的是 awk 脚本,而不是 bash 脚本。 awk 和 bash 是 2 个不同的独立工具,每个工具都有自己的范围、语法和语义。与 bash 或任何其他 shell 相比,Awk 更类似于 C。
  • @EdMorton,感谢您的帮助。你和@Inian 在我今晚的工作中发挥了重要作用。至于空格和缩进,我完全同意,但我不知道该怎么做,我的时间是凌晨 3 点。我不得不叫它一个晚上。我以前从未使用过awkgawk,对它们一无所知。我刚刚检查过,gawk --version 显示我有 4.1.4,当我尝试执行您所做的gawk -o- 格式化技巧时,我没有得到任何有用的东西。它就在那里,所以如果我反复按 Enter,我会看到 (0,0):(1,1):(2,2): 等。我做错了什么吗?
  • @EdMorton,我明白你现在对 "regex pattern"/regex pattern/ 的意思了。见这里:gnu.org/software/gawk/manual/html_node/Computed-Regexps.html“要将反斜杠转换为字符串中的正则表达式,您必须键入两个反斜杠。” 而且,“鉴于您可以使用正则表达式和字符串常量来描述正则表达式,这你应该使用吗?答案是“正则表达式常量”,原因有几个”。因此,该评论现在得到了赞成。谢谢。

标签: linux git awk


【解决方案1】:

这应该是一个小错字(很可能),因为awk 中的printf() 在格式说明符之后需要,

printf "-%-8s:", left++ line
#             ^^^

【讨论】:

    【解决方案2】:

    1/3:错误修复

    @Inian was correct:我只需要在参数之间使用逗号。我已经投入了工作(自发布此问题以来可能长达约 20~30 小时)并且我现在在使用 awk 的基础知识方面相当不错。我学到了很多东西。

    为了回答这个问题,这是我在@Inian 根据他的反馈发布他的答案后立即提出的解决方案。要关注的关键部分是printf 调用。请注意,我在格式字符串和之后的每个参数之间添加了逗号。正如他所说,这就是解决办法。

    重点关注的部分:

    printf "-%+4s     :%s\n", left++, line
    printf "+%+4s     :%s\n", right++, line
    printf " %+4s,%+4s:%s\n", left++, right++, line
    

    上下文中的全部内容:

    git diff HEAD~..HEAD --color=always | \
      gawk '{bare=$0;gsub("\033[[][0-9]*m","",bare)};\
        match(bare,"^@@ -([0-9]+),[0-9]+ [+]([0-9]+),[0-9]+ @@",a){left=a[1];right=a[2];next};\
        bare ~ /^(---|\+\+\+|[^-+ ])/{print;next};\
        {line=gensub("^(\033[[][0-9]*m)?(.)","\\2\\1",1,$0)};\
        bare~/^-/{printf   "-%+4s     :%s\n", left++, line;next};\
        bare~/^[+]/{printf "+%+4s     :%s\n", right++, line;next};\
        {printf            " %+4s,%+4s:%s\n", left++, right++, line;next}'
    

    这是我通过将上述脚本复制并粘贴到我的终端中得到的一些示例输出。如果您想完全复制此内容,请转到 git clone my dotfiles repo 并运行 git checkout 4386b089f163d9d5ff26d277b53830e54095021c。然后,将上述脚本复制并粘贴到您的终端中。输出看起来相当不错。左边的数字和事物的对齐现在看起来不错:

    $     git diff HEAD~..HEAD --color=always | \
    >       gawk '{bare=$0;gsub("\033[[][0-9]*m","",bare)};\
    >         match(bare,"^@@ -([0-9]+),[0-9]+ [+]([0-9]+),[0-9]+ @@",a){left=a[1];right=a[2];next};\
    >         bare ~ /^(---|\+\+\+|[^-+ ])/{print;next};\
    >         {line=gensub("^(\033[[][0-9]*m)?(.)","\\2\\1",1,$0)};\
    >         bare~/^-/{printf   "-%+4s     :%s\n", left++, line;next};\
    >         bare~/^[+]/{printf "+%+4s     :%s\n", right++, line;next};\
    >         {printf            " %+4s,%+4s:%s\n", left++, right++, line;next}'
    diff --git a/useful_scripts/git-diffn.sh b/useful_scripts/git-diffn.sh
    index 22c74e2..cf8ba08 100755
    --- a/useful_scripts/git-diffn.sh
    +++ b/useful_scripts/git-diffn.sh
       49,  49: #   4. `git-gs_diffn`
       50,  50: #   3. `gs_git-diffn`
       51,  51: 
    +  52     :+# FUTURE WORK:
    +  53     :+# 1. Make work with standard awk?
    +  54     :+#    This has been tested on Linux Ubuntu 18.04. If anyone can't get this working on their system,
    +  55     :+#    such as in the git bash terminal that comes with Git for Windows, or on MacOS, due to 
    +  56     :+#    compatibility probems with `gawk`, I can rewrite the few places relying on `gawk` extensions
    +  57     :+#    to just use basic awk instead. That should solve any compatibility problems, but there's no
    +  58     :+#    sense in doing it if there's no need. If I ever need to do this in the future though, I'm
    +  59     :+#    going to need this trick to obtain a substring using standard awk:
    +  60     :+#    https://stackoverflow.com/questions/5536018/how-to-print-matched-regex-pattern-using-awk/5536342#5536342
    +  61     :+#   1. Also, look into this option in gawk for testing said compatibility: 
    +  62     :+#     1. `--lint` - https://www.gnu.org/software/gawk/manual/html_node/Options.html
    +  63     :+#     1. `--traditional` and `--posix` - https://www.gnu.org/software/gawk/manual/html_node/Compatibility-Mode.html
    +  64     :+#   1. Currently, `--lint` is telling me that the 3rd argument to `match()` (ie: the array 
    +  65     :+#      parameter) is a gawk extension.
    +  66     :+
       52,  67: # References:
       53,  68: # 1. This script borrows from @PFudd's script here:
       54,  69: #    https://stackoverflow.com/questions/24455377/git-diff-with-line-numbers-git-log-with-line-numbers/33249416#33249416
      133, 148: # "41", "42", etc. codes is this:
      134, 149: #       ^(\033\[(([0-9]{1,2};?){1,10})m)?
      135, 150: 
    + 151     :+# Be sure to place all args (`"$@"`) AFTER `--color=always` so that if the user passes in
    + 152     :+# `--color=never` or `--no-color` they will override my `--color=always` here, since later
    + 153     :+# options override earlier ones.
      136, 154: git diff --color=always "$@" | \
      137, 155: gawk \
      138, 156: '
    

    这是一个显示漂亮颜色输出的屏幕截图:

    原始脚本,如下所示:

    git diff HEAD~..HEAD --color=always | \
      gawk '{bare=$0;gsub("\033[[][0-9]*m","",bare)};\
        match(bare,"^@@ -([0-9]+),[0-9]+ [+]([0-9]+),[0-9]+ @@",a){left=a[1];right=a[2];next};\
        bare ~ /^(---|\+\+\+|[^-+ ])/{print;next};\
        {line=gensub("^(\033[[][0-9]*m)?(.)","\\2\\1",1,$0)};\
        bare~/^-/{print "-"left++ ":" line;next};\
        bare~/^[+]/{print "+"right++ ":" line;next};\
        {print "("left++","right++"):"line;next}'
    

    产生看起来很糟糕(相比之下)、未对齐的输出:

    $     git diff HEAD~..HEAD --color=always | \
    >       gawk '{bare=$0;gsub("\033[[][0-9]*m","",bare)};\
    >         match(bare,"^@@ -([0-9]+),[0-9]+ [+]([0-9]+),[0-9]+ @@",a){left=a[1];right=a[2];next};\
    >         bare ~ /^(---|\+\+\+|[^-+ ])/{print;next};\
    >         {line=gensub("^(\033[[][0-9]*m)?(.)","\\2\\1",1,$0)};\
    >         bare~/^-/{print "-"left++ ":" line;next};\
    >         bare~/^[+]/{print "+"right++ ":" line;next};\
    >         {print "("left++","right++"):"line;next}'
    diff --git a/useful_scripts/git-diffn.sh b/useful_scripts/git-diffn.sh
    index 22c74e2..cf8ba08 100755
    --- a/useful_scripts/git-diffn.sh
    +++ b/useful_scripts/git-diffn.sh
    (49,49): #   4. `git-gs_diffn`
    (50,50): #   3. `gs_git-diffn`
    (51,51): 
    +52:+# FUTURE WORK:
    +53:+# 1. Make work with standard awk?
    +54:+#    This has been tested on Linux Ubuntu 18.04. If anyone can't get this working on their system,
    +55:+#    such as in the git bash terminal that comes with Git for Windows, or on MacOS, due to 
    +56:+#    compatibility probems with `gawk`, I can rewrite the few places relying on `gawk` extensions
    +57:+#    to just use basic awk instead. That should solve any compatibility problems, but there's no
    +58:+#    sense in doing it if there's no need. If I ever need to do this in the future though, I'm
    +59:+#    going to need this trick to obtain a substring using standard awk:
    +60:+#    https://stackoverflow.com/questions/5536018/how-to-print-matched-regex-pattern-using-awk/5536342#5536342
    +61:+#   1. Also, look into this option in gawk for testing said compatibility: 
    +62:+#     1. `--lint` - https://www.gnu.org/software/gawk/manual/html_node/Options.html
    +63:+#     1. `--traditional` and `--posix` - https://www.gnu.org/software/gawk/manual/html_node/Compatibility-Mode.html
    +64:+#   1. Currently, `--lint` is telling me that the 3rd argument to `match()` (ie: the array 
    +65:+#      parameter) is a gawk extension.
    +66:+
    (52,67): # References:
    (53,68): # 1. This script borrows from @PFudd's script here:
    (54,69): #    https://stackoverflow.com/questions/24455377/git-diff-with-line-numbers-git-log-with-line-numbers/33249416#33249416
    (133,148): # "41", "42", etc. codes is this:
    (134,149): #       ^(\033\[(([0-9]{1,2};?){1,10})m)?
    (135,150): 
    +151:+# Be sure to place all args (`"$@"`) AFTER `--color=always` so that if the user passes in
    +152:+# `--color=never` or `--no-color` they will override my `--color=always` here, since later
    +153:+# options override earlier ones.
    (136,154): git diff --color=always "$@" | \
    (137,155): gawk \
    (138,156): '
    

    截图:

    2/3:使数字也着色:

    回答我问题的第二部分:

    此外,数字和 +/- 符号应分别为绿色和红色,就像在正常的 git diff 输出中一样。

    然后我将红色 (\033[31m) 和绿色 (\033[32m) 的一些 ANSI 颜色代码添加到如下所示的倒数第三行和倒数第二行:

    git diff HEAD~..HEAD --color=always | \
      gawk '{bare=$0;gsub("\033[[][0-9]*m","",bare)};\
        match(bare,"^@@ -([0-9]+),[0-9]+ [+]([0-9]+),[0-9]+ @@",a){left=a[1];right=a[2];next};\
        bare ~ /^(---|\+\+\+|[^-+ ])/{print;next};\
        {line=gensub("^(\033[[][0-9]*m)?(.)","\\2\\1",1,$0)};\
        bare~/^-/{printf   "\033[31m-%+4s     :%s\n", left++, line;next};\
        bare~/^[+]/{printf "\033[32m+%+4s     :%s\n", right++, line;next};\
        {printf                    " %+4s,%+4s:%s\n", left++, right++, line;next}'
    

    并得到了这个更好看的输出。注意最左边的数字现在也被着色了:

    3/3:最后:

    然后:

    1. 对上面的代码进行了几天的剖析
    2. 疯狂地学习awk
    3. 扔掉上面的整个代码,因为它
      1. 无法阅读且格式严重
      2. 做了一些没有任何意义且不需要的非常奇怪的事情,并且
      3. 没有处理任何边缘情况或自定义 git diff 颜色
    4. 保留了绝对巧妙和完美的非常好的部分,并且
    5. 写了this really nice and full implementation of git diffn,其中:
      1. 处理我能想到的所有边缘情况
      2. 充当git diff 的直接替代品
      3. 处理所有可能的颜色和文本格式(据我所知),并且
      4. 无论有没有颜色,都能产生非常好的输出

    请参阅此处以获取git diffn 信息和安装说明:Git diff with line numbers (Git log with line numbers)

    结束。

    【讨论】:

      猜你喜欢
      • 2020-01-06
      • 2014-08-18
      • 1970-01-01
      • 1970-01-01
      • 2019-03-04
      • 1970-01-01
      • 2021-10-20
      • 2014-04-03
      相关资源
      最近更新 更多