カスタムオートコンプリート:ファイル名のスペース処理

カスタムオートコンプリート:ファイル名のスペース処理

少し背景情報です。この質問はこれに対するフォローアップです。Bashリモートオートコンプリート:「スタート」ディレクトリの変更

とにかく、私はカスタムオートコンプリートbashスクリプトを書いています。cd特定のディレクトリ(必ずしも現在のディレクトリである必要はありません)から名前を取得したいことを除いて、オートコンプリート機能は以前と同じように機能したいと思います。ファイル名にスペースが含まれていない場合は正常に動作します。

簡単な例です。名前を取得するディレクトリに2つのファイルがあるとします。a_fileanother file(スペースに注意してください)。時には次のように進行します。

my_commandTABTAB
a_file file another

プレゼンテーションは完璧ではありませんanother file。希望の出力は次のとおりです。また、スペースを自動的にエスケープしたいと思います。anotherfilefile_1 another file

my_command anoTAB
my_command another\ file

私のスクリプトは次のとおりです

#!/bin/bash

_get_file_list()
{
    dir="/一部/パス/"
    CD $ディレクトリ
    *検索 - 最大深さ0
}

_GetOptMyCommand()
{
    地域電流

    完了=()
    現在=${COMP_WORDS[COMP_CWORD]}

    ケース "$cur"
    -*)
        COMPREPLY=( $( compgen -W "-h -l --help --list --" -- "$cur" ) );;
    *)
        COMPREPLY=( $( compgen -W "$(_get_file_list)" -- "$cur" ) );;
    イサク

    0を返す
}

フル -F _GetOptMyCommand my_command

ファイル名のスペースをどのように処理し、オートコンプリートスクリプトを次のように作成できますかcd

ベストアンサー1

この場合compgen、これを使用する方が良いかもしれません。find

すでにシステム完了スクリプトがある可能性があります。たとえば、試してみてください。

locate bash_completion

Debian バリアントでは、次のようになります。

/usr/share/bash-completion/bash_completion

たとえば、どこで見つけることができますか_filedir?最も簡単な方法は次のとおりです。

*)
    pushd "/some/path" >/dev/null
    _filedir
    popd >/dev/null

これがオプションでない場合は、次のように開始する方法になります。

_comp_by_path()
{
    local opt cur dir
    local IFS=$'\n' x tmp
    local -a tokens

    opt="$1"
    cur="$2"
    dir="$3"

    # Enter target directory
    pushd "$dir" >/dev/null

    # Get directories, filtered against current
    [[ "$opt" != "-f" ]] && \
    x=$( compgen -d -- "$cur" ) &&
    while read -r tmp; do
        tokens+=( "$tmp" )
    done <<< "$x"

    # Get files, filtered against current
    [[ "$opt" != "-d" ]] && \
    x=$( compgen -f -- "$cur" ) &&
    while read -r tmp; do
        tokens+=( "$tmp" )
    done <<< "$x"

    # If anything found
    if [[ ${#tokens[@]} -ne 0 ]]; then
        # Make sure escaping is OK
        compopt -o filenames 2>/dev/null
        COMPREPLY+=( "${tokens[@]}" )
    fi

    # Go back
    popd >/dev/null
}

_GetOptMyCommand()
{
    local cur

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

    case "$cur" in
    -*)
        COMPREPLY=( $( compgen -W "-h -l --help --list --" -- "$cur" ) );;
    *)
        _comp_by_path "any" "$cur" "/some/path"
    esac
}

complete -F _GetOptMyCommand my_command

使用されるバリエーションはfind次のとおりです。

_zaso()
{
    local dir="$1"

    pushd "$dir" >/dev/null
    find * -maxdepth 0 2>/dev/null
    popd >/dev/null
}

_comp_with_find()
{
    local cur dir      
    local IFS=$'\n'

    cur="$1"
    dir="$2"

    compopt -o filenames 2>/dev/null
    COMPREPLY=( $( compgen -W "$(_zaso "$dir")" -- "$cur" ) );
}

また、printfBashにはオプションがあります%q。したがって、引用符付き文字列を生成するには、次のオプションを使用できます。

find * -maxdepth 0 2>/dev/null && \
while read -r tmp; do
    printf "%q\n" "$tmp"
done <<< "$x"

また、ファイル名に改行文字を含めることはできず、そのほとんどが破損する可能性があります。まだ\0withを使用する方法が見つかりませんcompgen

おすすめ記事