在bash脚本中自动完成文件名

时间:2013-12-29 17:20:55

标签: bash

我正在尝试模仿bash文件的完成情况 假设我有以下文件:

TEST1
   TEST2

输入字符串为“ te ”我想获得输出“ test

这是我当前的尝试($c是输入字符串):

l=1
q="$c"
for j in $(ls -A | grep "^$c"); do
    if [ "${j/$c}" != "$j" ]; then 
            n=$(ls -A | grep ^$j | wc -l)
            if [ $n -gt $l ]; then 
                    q="$j"  
            fi      
    fi
done
c="$q"
echo $c

感谢您的帮助

3 个答案:

答案 0 :(得分:1)

我倾向于认为没有办法从完成引擎中获取它,因为它不是GNU Bash的一部分而是Readline。但至少我们可以使用compgen获取可能的完成列表。找到最长公共前缀的实现应该不是问题。所以......

#!/bin/bash

SCRIPTNAME="${0##*/}"
USAGE="Usage: $SCRIPTNAME <prefix>

Print common prefix of possible file name completions. Like <TAB> but to
stdout."

(( $# == 1 )) || { printf >&2 '%s\n' "$USAGE"; exit 1; }

PREFIX="$1"

commonprefix() {
    (( $# >= 2 )) || { 
        echo "$1"
        return 0
    }
    local -i i N M
    for ((i=0; i<=${#1}; i++)); do 
        for ((N=1; N<=$#-1; N++)); do
            let M=$N+1
            [[ ${!N:i:1} == ${!M:i:1} ]] || break 2
        done
    done
    echo "${1:0:i}"
}

readarray -t COMPLETIONS < <(compgen -f "$PREFIX")
commonprefix "${COMPLETIONS[@]}"

答案 1 :(得分:0)

为了表明你正在考虑正确的方向,我让你的代码工作:

#!/bin/bash

c=$1
q="$c"
for j in $c*; do
    if [ "${j/$c}" != "$j" ]; then
        startn=$(ls -1A | grep -c "^${j:0:$((${#c} + 1))}")
        for (( i=${#c}; i <= ${#j}; i++ )); do
            n=$(ls -1A | grep -c "^${j:0:$i}")
            if [ "$n" -lt "$startn" ]; then
                q="${j:0:$((i - 1))}"
            elif [ "$n" -le "$startn" ]; then
                q="${j:0:$i}"
            fi
        done
    fi
done
c="$q"
echo "$c"

但是,它只是一个概念证明,不使用它。请参阅德米特里亚历山德罗夫的答案以获得一个很好的解决方案。

答案 2 :(得分:0)

虽然德米特里亚历山德罗夫已经提供了更好的解决方案,但我仍然希望在等待答案时发布我自己的一个:

l=1
while [ -n $l ]; do
    l=${#c}
    a=$(ls -A | grep "^$c" | wc -l)
    q=$c
    for i in $(ls -A | grep "^$q"); do
            if [ $i == $q ]; then 
                    unset l
                    break
            else
                    v=$(ls -A | grep "^$q${i:$l:1}" | wc -l)
                    if [ $v == $a ]; then 
                            q="$c${i:$l:1}"
                            break
                    fi
            fi
    done
    if [ $c == $q ]; then break; fi
    c=$q
done
echo $c

它适用于我的所有测试,但速度很慢(尽管可以优化)。