2016-12-30 93 views
4

我有一个shell脚本(我将其导入到.bashrc中),它允许我从任何地方跳到我的项目目录。Shell脚本在运行时认为目录不存在

cdp(){ 
    proj="~/dev/projects/[email protected]/" 
    builtin cd $proj 
} 

_my_cdp() 
{ 
    local cur opts 
     cur="${COMP_WORDS[COMP_CWORD]}" 
     opts=$(ls ~/dev/projects/) 
     COMPREPLY=($(compgen -W "${opts}" -- ${cur})) 
} 

complete -o nospace -F _my_cdp cdp 

的问题是,在第3行的cd说:

bash: cd: ~/dev/projects/jsonparse/: No such file or directory 

以下是完整的控制台输出显示错误和证明的目录存在。

amflare:~$ cd dev/projects/ (go to dir) 
amflare:~/dev/projects$ ls -al (look at contents) 
total 68 
drwxrwxr-x 17 www-data amflare 4096 Dec 29 13:11 . 
drwxrwxr-x 4 amflare amflare 4096 Dec 6 17:32 .. 
drwxrwxr-x 3 www-data amflare 4096 Dec 22 17:33 bot 
drwxrwxr-x 3 www-data amflare 4096 Dec 20 15:17 jsonparse 
drwxrwxr-x 3 www-data amflare 4096 Dec 28 19:58 magic 
drwxrwxr-x 2 www-data amflare 4096 Nov 11 14:42 test 
amflare:~/dev/projects$ cd (go to home) 
amflare:~$ cdp (run autocomplete) 
bot   jsonparse magic  test 
amflare:~$ cdp jsonparse (pick target) 
bash: cd: ~/dev/projects/jsonparse/: No such file or directory 
amflare:~$ (still in home) 

我已经尝试了所有我能想到的以及Google为其他发行版(我在Ubuntu GNOME 16.04上)回馈的一些东西。无论我做什么,shell脚本都不会承认~/dev/projects/内存在任何东西。此外,当我有.bashrc本身的功能时,它不起作用,所以我不认为它是一个子外壳问题。如果您需要更多信息,请告诉我。谢谢。

+0

这是因为代字号未扩展。使用'proj =〜/“dev/projects/$ @ /”',并用引号括起来。或者使用变量'HOME':'proj =“$ HOME/dev/projects/$ @”'。请注意,使用'$ @'并不是很好。如果有几个参数,你想要什么? –

+0

考虑通过http://shellcheck.net/运行此代码 - 有*很多*错误;这可能无法抓住所有东西,但这是一个开始的地方。 –

+0

...见,f/e,[ParsingLs](http://mywiki.wooledge.org/ParsingLs) - 'ls'是程序使用不当的工具。而且缺乏引用导致它自己的问题。 –

回答

5

这是因为代字号未扩展。使用proj=~/"dev/projects/[email protected]/",并用引号括起来。或使用变量HOMEproj="$HOME/dev/projects/[email protected]"。但请注意,使用[email protected]并不是很好。如果有几个参数,你想要什么?另外,请勿使用opts=$(ls ~/dev/projects/)。直接使用compgen像这样:

cdp() { 
    local proj=~/dev/projects/ 
    builtin cd "$proj$1" 
} 

_my_cdp() { 
    local proj=~/dev/projects/ 
    local i p 
    COMPREPLY=() 
    while IFS= read -r i; do 
     printf -v p '%q' "${i#"$proj"}" 
     COMPREPLY+=("$p") 
    done < <(compgen -d -- "$proj$2") 
} 

完成时,将建成功能_my_cdp将作为参数$2正在完成的话。我们给compgen -d(前缀$proj),并循环遍历结果(结果每行输出一个 - 所以是的,如果你的目录中有新行,它会中断)。找到每个名称后,我们使用printf '%q'引用它,同时使用参数扩展删除前缀$proj。如果目录名称包含空格或有趣的字符(例如,glob字符),则使用引号以避免中断,并且我们一次填充一个字段的数组COMPREPLY。这是一种处理完成的相当健壮的方法(但不是100%不可破解的,但它会为你的非疯狂目录名称做这项工作!)。

+0

这是问题所在。谢谢。至于$ @,我基于这个别人的代码,并没有打扰改变它。我现在虽然。 – amflare

+1

@tbirrell:回答编辑略有更好的完成! –

+0

啊。干杯!我实际上正在试图弄清楚这一点。这里有很多移动部件,我不明白。编码高尔夫球风格是否会让球迷难以接受? – amflare