cd 以外のコマンドの Bash オートコンプリート変数

cd 以外のコマンドの Bash オートコンプリート変数

環境変数があります$SCRIPT。通常、オートコンプリートを使用できます

vim $SC<tab>

期待どおりに操作が完了します。一部のシステムでは機能しません。 bash完了がロードされましたが、この場合、完了はディレクトリ(cd $SCRIPT_DIREC<tab>動作中)でのみ機能します。

主にbash 4.2に問題があります。

何がshoptそれを可能にすることができますか?

編集:私の設定を動作させるBash 4.3と動作しないBash 4.2(Ubuntu Server 12.04)と比較しましたshopt

ベストアンサー1

特に問題は、シェル組み込みコマンドは<tab>パラメータ名を拡張できますが、外部コマンドは拡張できないことです。これが機能する理由は次のとおりですcdechoその他readの組み込み機能は、OPが期待どおりに機能し続けます。

店とは何の関係もありません。

/etc/bash_completionbash_completionライブラリ(私の12.04.4システム)にあります。バージョン 1.3 には、このような競合状況を引き起こす要因があります。 1.99以前のどこかで修正されました。

bash_completionライブラリはソースコードがあれば自動的にインポートされる~/.bash_completionため、次の内容を含むファイルを生成して12.04.4ライブラリで機能しない関数定義をオーバーロードすることをお勧めします。私はいくつかの小さなテストを行いましたが、私が使用したマシンはこれの影響を受けませんでしたので、注意が必要です。

# following functions are direct copy/pastes from
# bash_completion RELEASE: 1.99
# overloading `_longopt()' and adding `_variables()' and `_init_completion()'
# appears to be all that is needed to correct this.
# 
# http://unix.stackexchange.com/questions/126300/bash-autocomplete-variables-for-other-commands-than-cd

_init_completion()
{
    local exclude= flag outx errx inx OPTIND=1
    while getopts "n:e:o:i:s" flag "$@"; do
        case $flag in
            n) exclude+=$OPTARG ;;
            e) errx=$OPTARG ;;
            o) outx=$OPTARG ;;
            i) inx=$OPTARG ;;
            s) split=false ; exclude+== ;;
        esac
    done
    # For some reason completion functions are not invoked at all by
    # bash (at least as of 4.1.7) after the command line contains an
    # ampersand so we don't get a chance to deal with redirections
    # containing them, but if we did, hopefully the below would also
    # do the right thing with them...
    COMPREPLY=()
    local redir="@(?([0-9])<|?([0-9&])>?(>)|>&)"
    _get_comp_words_by_ref -n "$exclude<>&" cur prev words cword
    # Complete variable names.
    _variables && return 1
    # Complete on files if current is a redirect possibly followed by a
    # filename, e.g. ">foo", or previous is a "bare" redirect, e.g. ">".
    if [[ $cur == $redir* || $prev == $redir ]]; then
        local xspec
        case $cur in
            2'>'*) xspec=$errx ;;
            *'>'*) xspec=$outx ;;
            *'<'*) xspec=$inx ;;
            *)
                case $prev in
                    2'>'*) xspec=$errx ;;
                    *'>'*) xspec=$outx ;;
                    *'<'*) xspec=$inx ;;
                esac
                ;;
        esac
        cur="${cur##$redir}"
        _filedir $xspec
        return 1  
    fi
    # Remove all redirections so completions don't have to deal with them.
    local i skip  
    for (( i=1; i < ${#words[@]}; )); do
        if [[ ${words[i]} == $redir* ]]; then
            # If "bare" redirect, remove also the next word (skip=2).
            [[ ${words[i]} == $redir ]] && skip=2 || skip=1
            words=( "${words[@]:0:i}" "${words[@]:i+skip}" )
            [[ $i -le $cword ]] && cword=$(( cword - skip ))
        else
            i=$(( ++i ))
        fi
    done
    [[ $cword -eq 0 ]] && return 1
    prev=${words[cword-1]}
    [[ ${split-} ]] && _split_longopt && split=true
    return 0
}

_variables()
{
    if [[ $cur =~ ^(\$\{?)([A-Za-z0-9_]*)$ ]]; then
        [[ $cur == *{* ]] && local suffix=} || local suffix=
        COMPREPLY+=( $( compgen -P ${BASH_REMATCH[1]} -S "$suffix" -v -- \
            "${BASH_REMATCH[2]}" ) )
        return 0  
    fi
    return 1
}

_longopt()
{   
    local cur prev words cword split
    _init_completion -s || return
    case "${prev,,}" in
        --help|--usage|--version)
            return 0
            ;;
        --*dir*)
            _filedir -d
            return 0
            ;;
        --*file*|--*path*)
            _filedir
            return 0
            ;;
        --+([-a-z0-9_]))
            local argtype=$( $1 --help 2>&1 | sed -ne \
                "s|.*$prev\[\{0,1\}=[<[]\{0,1\}\([-A-Za-z0-9_]\{1,\}\).*|\1|p" )
            case ${argtype,,} in
                *dir*)
                    _filedir -d
                    return 0
                    ;;
                *file*|*path*)
                    _filedir
                    return 0
                    ;;
            esac
            ;;
    esac
    $split && return 0
    if [[ "$cur" == -* ]]; then
        COMPREPLY=( $( compgen -W "$( $1 --help 2>&1 | \
            sed -ne 's/.*\(--[-A-Za-z0-9]\{1,\}=\{0,1\}\).*/\1/p' | sort -u )" \
            -- "$cur" ) )
        [[ $COMPREPLY == *= ]] && compopt -o nospace
    elif [[ "$1" == @(mk|rm)dir ]]; then
        _filedir -d
    else
        _filedir
    fi
}

おすすめ記事