Bash 自动完成:列出其他目录中的文件和目录

Bash 自动完成:列出其他目录中的文件和目录

我编写了一个名为 的脚本prpsls,它在目录中创建或编辑文件~/proposals

现在我正在为其编写自动完成脚本,并且我正在尝试以某种方式设置它,在我点击之后标签,无论当前工作目录如何,complete内置都会列出目录中的文件和目录。~/proposals

我想要实现的行为与我所做的完全一样complete -f prpsls,但我希望它始终完成目录的内容,而不是列出当前目录中的文件和目录~/proposals

例如,当我写ls标签, 表明:

$ pwd
/home/user/base_directory
$ ls
file_01   file_02    subdir_01/

如果我写subd并且标签,它会自动完成为subdir_01.如果我标签再次,它显示的内容dir_01

$ ls subdir_01/
file_03    subdir_02/

我正在寻找的行为是类似的:

$ pwd
/home/user/any/directory/it/should/not/matter
$ prpsls # Tab here
proposal_01    proposal_02    job_01/
$ prpsls job_01/ # Tab again
proposal_03    proposal_draft

complete我的问题是:是否可以通过内置实现此行为?如果没有,我怎样才能实现这种行为?

我希望我可以通过标志告诉complete哪个目录用作基本目录,但我看到的与目录相关的唯一标志是-dwhich 与 相同-A directory,它生成目录列表。

有趣的是,如果我使用compgen -f "~/proposals/",它列出以下位置的文件和目录~/proposals

$ pwd
/home/user/any/directory/it/should/not/matter
$ compgen -f "~/proposals/"
~/proposals/job_01
~/proposals/proposal_01
~/proposals/proposal_02

我见过问题,但是:

  • 接受的答案不适用于嵌套目录。 (IE标签并查看目录的内容)
  • 答案CDPATH会给其他命令带来更多混乱。
  • 答案compgen也不适用于嵌套目录。

答案1

基于这个很棒的答案我为 command 编写了这个完成foo,它递归地完成文件和目录~/foodir

FOO_DIR=$HOME/foodir/

_foo_compgen_filenames() {
    local cur="$1"

    # Files, excluding directories:
    grep -v -F -f <(compgen -d -P ^ -S '$' -- $FOO_DIR"$cur") \
        <(compgen -f -P ^ -S '$' -- $FOO_DIR"$cur") |
        sed -e 's|^\^'$FOO_DIR'||' -e 's/\$$/ /'

    # Directories:
    compgen -d -S / -- $FOO_DIR"$cur" | sed -e 's|'$FOO_DIR'||'
}

_foo_complete() {
    local cur=${COMP_WORDS[COMP_CWORD]}
    COMPREPLY=( $(_foo_compgen_filenames "$cur") )
}

complete -o nospace -F _foo_complete foo

诀窍在于让compgen补全引擎补全 中文件的完整路径FOO_DIR,然后在FOO_DIR将其发送到 之前从补全中删除该路径complete。还有在目录名称末尾添加斜杠的问题,这不是给定的,也compgen没有仅返回文件的本机方法(但确实有一种仅返回目录的方法)。

答案2

我尝试并找到了一些如何修复它的方法和想法。

专业人士可以改进我的方式并创建更好/完美的解决方案。

我的系统是 Debian GNU/Linux 10 (buster) 4.19.0-16-amd64,带有 KDE 和 GNOME

第一部分:

  1. 启动一个新的外壳

  2. 创建工作目录/home/user/ComBashcd进入其中

  3. 创建一个脚本,mytab我们将此脚本绑定到完整的命令

    现在mytab看起来像:

    #!/bin/bash
    echo "MYTAB"
    
  4. chmod +x mytab

  5. px为完整命令创建第二个脚本

    现在px看起来像:

    #/usr/bin/env bash
    echo "PX"
    
  6. chmod +x px

  7. 现在我们开始我们的px脚本

    source px
    

    或者

    ./px
    

    或者

    . ./px
    

    输出应该是“PX”(它有效)

  8. bin/创建一个名为in 的新文件夹/home/user/ComBash

    mkdir bin
    

    我们的文件现在是

    mytab        | script
    px           | script
    bin/         | folder
    
  9. 现在安装mytabbin/我们的workdir | 路径中/home/user/ComBash/binmytab删除/home/user/ComBash/

    install mytab bin/mytab && rm mytab
    
  10. 现在将workdirbin/文件夹添加到$PATH

    PATH="/home/user/ComBash/bin:${PATH}"
    

    或者

    PATH="${PATH}:/home/user/ComBash/bin"
    

    检查与

    echo $PATH 
    
  11. 检查是否mytab有效:

    • myt+TAB并按Enter
    • mytabEnter
    • 输出是“MYTAB”(它有效)
  12. 在文件夹内创建一些文件夹、子文件夹和空文件,我们需要这些文件夹和文件来检查TAB+是否TAB有效并检查 TAB|TAB 显示的内容

现在我们有了第二部分的结构,该解决方案仅适用于当前 shell

如果我们关闭并启动一个新的 shell,/home/user/ComBash/binin$PATH被删除并且 bash 找不到mytab中的脚本/home/user/ComBash/bin,那么每次启动新 shell 时都必须重复步骤 9.(设置 $PATH)。

如果您不想每次启动 shell 时都重复步骤 9,则可以永久添加/home/user/ComBash/bin$PATH

第二部分:

  1. 打开并编辑px文件

    我也尝试了很多这个命令,但我现在不会解释它们,你可以尝试查看结果,只需取消注释并编辑你想尝试的行。

    现在 px 看起来像:

    #/usr/bin/env bash
    #complete -f mytab
    #complete -D -F "/home/user/ComBash" mytab
    #complete -W "$(find /home/user/ComBash/ -path "" -prune -o \( -type d -ls \) -o \( -type f -ls \) | cut -d/ -f 5-)" mytab
    #complete -W "$(find /home/user/ComBash/ -path "" -prune -o \( -type d -ls \) -o \( -type f -ls \) | cut -d/ -f 2- | sed 's/$/\//')" mytab
    #complete -W "$(find /home/user/ComBash/ -path "" -prune -o \( -ls \)))" mytab
    #complete -W "$(ls -R ${MYPATH} | grep /)" mytab
    MYPATH="/home/user/ComBash/"
    complete -W "$(ls -R ${MYPATH})" mytab
    

    我们将完整的命令绑定到mytab脚本中

    -W意味着我们给出完整的单词列表

    我们得到带有 的单词列表ls -R

    ls -R列出给定路径中的所有文件、子文件、目录和子目录

  2. 我们启动 px 脚本

    source px
    

    每次我们在脚本内进行更改时,都必须重新启动脚本(请参阅第 I 部分中的步骤 6)

    source px 
    
  3. 现在在 shell 中我们使用

    mytab+TAB

    /home/user/ComBash/我们可以看到给定路径 ( )中所有文件、子文件、目录和子目录的列表

    我们可以选择每个文件、子文件、目录和子目录,并使用 [TAB] 自动完成

    选择有效的子文件夹和 [TAB]

    如果我们按下Enter脚本mytab将回显“MYTAB”

  4. mytab让我们在 中编辑脚本/home/user/ComBash/bin

    现在mytab看起来像:

    #!/bin/bash
    MYPATH=/home/user/ComBash
    # echo $MYPATH
    echo $1
    DATA=$(find ${MYPATH} -name ${1})
    echo $DATA
     ####### DO SOMETHING #######
    

    $1px输出我们从脚本 搜索中收到的文件夹或文件DATA,并输出PATH文件夹或文件的

现在我们可以对当前文件或文件夹执行某些操作

mytab+TabEnter

相关内容