27
4

5 に答える 5

8

このあまり洗練されていない後処理ソリューションは、私にはうまくいくようです (GNU bash、バージョン 3.1.17(6)-release (i686-pc-cygwin))。(いつものようにボーダーケースをテストしなかった場合を除きます:))

物事を評価する必要はありません。引用符には2種類しかありません。

compgen はスペースをエスケープしたくないので、自分でスペースをエスケープします (単語が引用符で始まっていない場合のみ)。これには、エスケープされた値を持つ完全なリスト (ダブルタブ) の副作用もあります。ls はそれをしないので、それが良いかどうかはわかりません...

編集:単語内の単一および二重のクォートを処理するように修正されました。基本的に、3 つのアンエスケープを渡す必要があります :)。1 番目は grep の場合、2 番目は compgen の場合、最後は words コマンド自体の場合です。

_find_words()
{
    search=$(eval echo "$cur" 2>/dev/null || eval echo "$cur'" 2>/dev/null || eval echo "$cur\"" 2>/dev/null || "")
    grep -- "^$search" words.dat | sed -e "{" -e 's#\\#\\\\#g' -e "s#'#\\\'#g" -e 's#"#\\\"#g' -e "}"
}

_words_complete()
{
    local IFS=$'\n'

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

    COMPREPLY=( $( compgen -W "$(_find_words)" -- "$cur" ) )

    local escaped_single_qoute="'\''"
    local i=0
    for entry in ${COMPREPLY[*]}
    do
        if [[ "${cur:0:1}" == "'" ]] 
        then
            # started with single quote, escaping only other single quotes
            # [']bla'bla"bla\bla bla --> [']bla'\''bla"bla\bla bla
            COMPREPLY[$i]="${entry//\'/${escaped_single_qoute}}" 
        elif [[ "${cur:0:1}" == "\"" ]] 
        then
            # started with double quote, escaping all double quotes and all backslashes
            # ["]bla'bla"bla\bla bla --> ["]bla'bla\"bla\\bla bla
            entry="${entry//\\/\\\\}" 
            COMPREPLY[$i]="${entry//\"/\\\"}" 
        else 
            # no quotes in front, escaping _everything_
            # [ ]bla'bla"bla\bla bla --> [ ]bla\'bla\"bla\\bla\ bla
            entry="${entry//\\/\\\\}" 
            entry="${entry//\'/\'}" 
            entry="${entry//\"/\\\"}" 
            COMPREPLY[$i]="${entry// /\\ }"
        fi
        (( i++ ))
    done
}
于 2009-07-18T04:22:43.060 に答える
5
_foo ()
{
  words="bar one"$'\n'"bar two"
  COMPREPLY=()
  cur=${COMP_WORDS[COMP_CWORD]}
  prev=${COMP_WORDS[COMP_CWORD-1]}
  cur=${cur//\./\\\.}

  local IFS=$'\n'
  COMPREPLY=( $( grep -i "^$cur" <( echo "$words" ) | sed -e 's/ /\\ /g' ) )
  return 0
}

complete -o bashdefault -o default -o nospace -F _foo words 
于 2013-12-13T16:46:32.723 に答える
1

パイプ_find_wordsスルーsedし、各行を引用符で囲みます。"また、コマンド ラインを入力するときは、タブ補完する単語の前にまたはを必ず入力して'ください。そうしないと、この方法は機能しません。

_find_words() { cat words.dat; }

_words_complete()
{

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

  local IFS=$'\n'
  COMPREPLY=( $( compgen -W "$( _find_words | sed 's/^/\x27/; s/$/\x27/' )" \
                         -- "$cur" ) )

}

complete -F _words_complete words

コマンドライン:

$ words "ba░

tab

$ words "bar ░

tabtab

bar one  bar two
$ words "bar o░

tab

$ words "bar one" ░
于 2015-07-17T15:40:02.903 に答える