Makefile目标的Bash自动补全

61
假设我有一个简单的 makefile,像这样:
hello:
   echo "hello world"

bye:
   echo "bye bye"

然后在bash中我想要像这样的东西:

make h < tab >

这样它就可以自动完成为

make hello

我找到了一种简单的方法,如创建空文件hellobye,但我正在寻找更加复杂的方法。

8个回答

86
将以下内容添加到您的~/.bash_profile文件或~/.bashrc文件中。

Add this in your ~/.bash_profile file or ~/.bashrc file


返回结果: 将以下内容添加到您的~/.bash_profile文件或~/.bashrc文件中。
complete -W "\`grep -oE '^[a-zA-Z0-9_.-]+:([^=]|$)' ?akefile | sed 's/[^a-zA-Z0-9_.-]*$//'\`" make
这将在您的Makefile中搜索名为'Makefile'或'makefile'(请注意?akefile中的大写通配符),使用grep,并将其传输到bash中的complete命令,该命令用于指定如何自动完成参数。 -W标志表示complete命令的输入将是一个单词列表,这通过将grep的结果通过sed来实现,将其排列成理想的wordlist格式。
注意事项:
1. 您的make文件名为“GNUMakefile”或其他名称而不是“Makefile”或“makefile”。如果经常遇到此类标题,请相应更改正则表达式?akefile。 2. 在更改后忘记从~/.bash_profile或~/.bashrc文件中source。我提供了这个看似微不足道的细节,因为对于初学者来说可能不熟悉。 为使任何对bash文件的更改生效,请使用以下命令source它们:
source ~/.bashrc
source ~/.bash_profile

PS. 现在您还可以通过按两次[Tab]键来显示可能的 make 目标,就像在 bash 自动补全中一样。只需在输入 make 命令后加上空格,然后再按两次 [Tab] 键即可。


5
我个人使用的命令是:complete -W "\make -qp | sed -n -E 's/^([^.#\s][^:=])(:$|:\s+.$)/\1/p' | sort -u'`" make`。 - Jules Baratoux
4
我认为处理当前目录中没有Makefile的情况是有益的: complete -W "`([[ -r Makefile ]] && grep -oE '^[a-zA-Z0-9_-]+:([^=]|$)' Makefile || cat /dev/null) | sed 's/[^a-zA-Z0-9_-]*$//'`" make - sevenever
2
你的解决方案没有检测到包含点“.”的命令。 - famas23
@ahmedbhs已更新,包括识别“.”。 - Cibin Joseph
2
他们不应该考虑 .PHONY 和 .env 等,这是我的建议: complete -W "`grep -oE '^[a-zA-Z0-9_-][a-zA-Z0-9_.-]+:([^=]|$)' Makefile | sed 's/[^a-zA-Z0-9_-]*$//'`" make - famas23

14

有一个非常有用的软件包叫做 bash-completion,可用于大多数操作系统。它包含 Makefile 的命令补全功能。

(如果你使用的是 macOS,并且安装了 Homebrew,你可以通过 brew install bash-completion 命令来获取它。)


7
针对 macOS 系统,有一个名为 bash-completion@2 的软件包与 bash-completion 存在直接冲突。如果你的 bash 版本大于等于 4.1,则建议使用 @2 版本。然而需要注意的是,@2 版本似乎没有包含 Makefile 自动补全功能,因此像其他回答中所提到的那样,在 bashrc 中添加自定义规则可能会有所帮助。 - mirageglobe

14

这篇2010年的回答已经过时了 - 这里提到的项目似乎已经停止了。

这可能是你在寻找的东西吗?

http://freshmeat.net/projects/bashcompletion/

[Tab]键可以补全Makefile中的所有目标。该项目旨在为最常见的Linux / UNIX命令生成可编程补全程序,减少系统管理员和程序员每天需要输入的字符数。


3
链接已损坏。 - Jonas Stein
@JonasStein 谢谢,我打算删除这个帖子,因为我没有找到这个项目的替代链接。有很多比我的回答更新的答案。 - Kos
哎呀,我无法删除,因为它已被接受。我会留个备注。 - Kos
试试这个。https://github.com/scop/bash-completion - Ярослав Рахматуллин

3

这似乎是Debian Lenny中的默认设置:

$ grep Makefile /etc/bash_completion
    # make reads `GNUmakefile', then `makefile', then `Makefile'
    elif [ -f ${makef_dir}/Makefile ]; then
        makef=${makef_dir}/Makefile
    # before we scan for targets, see if a Makefile name was
    # deal with included Makefiles

这个文件的头部声明如下:
#   The latest version of this software can be obtained here:
#
#   http://bash-completion.alioth.debian.org/
#
#   RELEASE: 20080617.5

3
这是一个检查 .PHONY: 声明的完整脚本。
_make_phony_words() {
  local opt_revert

  if [ -n "${BASH_VERSION:-}" ]; then
    shopt -q nullglob || {
      opt_revert=1 ; shopt -s nullglob ;
    }

  elif [ -n "${ZSH_VERSION:-}" ]; then
    [[ -o nullglob ]] || {
      opt_revert=1 ; setopt nullglob
    }
  fi

  for f in ./?akefile ./*.make ; do
    sed -nEe '/^.PHONY/ { s/^.PHONY:[ ]?// ; p ; } ' "$f" | tr ' ' $'\n' | sort -u
  done

  if [ -n "$opt_revert" ]; then

    [ -n "${ZSH_VERSION:-}" ] && unsetopt nullglob
    [ -n "${BASH_VERSION:-}" ] && shopt -u nullglob
  fi
  unset opt_revert

}

_make_phony_complete() {
  local cur="${COMP_WORDS[COMP_CWORD]}"

  COMPREPLY+=( $(compgen -W "$( _make_phony_words )" -- ${cur}) )

}
complete -F _make_phony_complete make

2

强化版Makefile自动补全!

我对普通的自动补全有两个问题:

问题一

有时你需要调用类似于 make greet:himake greet:hola 这样的目标,就像给 Makefile 的目标名称添加命名空间。所以你的Makefile看起来像这样:

greet\:hola:
   echo "hola world"

# OR a .PHONY target
.PHONY: greet\:hi
greet\:hi:
   echo "hi world"

在这种情况下,在后自动完成不会显示,因为它在Makefile中使用\:,如上所示。

问题#2

在我的bash shell中,没有一种方法可以使用箭头键(或 CTRL-p / CTRL-n )浏览与我的输入匹配的所有 Makefile 目标列表。

基本上,我想在目标上使用模糊搜索(即 fzf )。 FZF Repo:https://github.com/junegunn/fzf

解决方案

安装FZF依赖项

使用Homebrew

您可以使用 Homebrew (在macOS或Linux上) 安装fzf。

brew install fzf
$(brew --prefix)/opt/fzf/install
使用Linux包管理器
包管理器 Linux发行版 命令
APK Alpine Linux sudo apk add fzf
APT Debian 9+/Ubuntu 19.10+ sudo apt-get install fzf
Conda conda install -c conda-forge fzf
DNF Fedora sudo dnf install fzf
Nix NixOS, etc. nix-env -iA nixpkgs.fzf
Pacman Arch Linux sudo pacman -S fzf
pkg FreeBSD pkg install fzf
pkgin NetBSD pkgin install fzf
pkg_add OpenBSD pkg_add fzf
XBPS Void Linux sudo xbps-install -S fzf
Zypper openSUSE sudo zypper install fzf

FZF和:兼容的自动补全命令

将以下内容添加到你的.bashrc文件中:

complete -W "\`grep -oE '^[a-zA-Z0-9_.-]+[\\:]*[a-zA-Z0-9_.-]+:([^=]|$)' ?akefile | sort | uniq | sed 's/[^a-zA-Z0-9_.-]*$//' | sed 's/[\]//g' | fzf\`" make

现在只需要输入make,然后按下回车键即可完成操作!
演示效果如下:
然后可以按照以下方式使用:
使用fzf制作,请参考此链接:make using fzf

0

我添加了一个在Makefile中遵循“include”指令的功能。因此,我的.bashrc文件看起来像这样:

function followMakefile() {
  grep -oE '^[a-zA-Z0-9_.-]+:([^=]|$)' ?akefile | sed 's/[^a-zA-Z0-9_.-]*$//'
  for x in `grep -E '^include' ?akefile | sed 's/include //'`
  do
    grep -oE '^[a-zA-Z0-9_.-]+:([^=]|$)' $x | sed 's/[^a-zA-Z0-9_.-]*$//'
  done
}
complete -W "\`followMakefile\`" make

-3
在Ubuntu 10.04中,引用以下文件:
. /etc/bash_completion

或在其前取消注释

/etc/bash.bashrc

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接